Подтвердить что ты не робот

HashSet содержит повторяющиеся записи

HashSet сохраняет только значения, когда метод equals говорит, что они одинаковы. Вот что я думал.

Но теперь я добавляю Elements в HashSet, где метод equals возвращает true, а размер набора все еще растет? извините, я смущен. Некоторые подсказки, где я ошибаюсь, будут приятными.

Element t1 = new Element(false, false, false, false);
Element t2 = new Element(true, true, true, true);
Element t3 = new Element(false, false, false, false);

if (t1.equals(t3))
    System.out.println("they're equal");

Set<Element> set = new HashSet<>();

set.add(t1);
set.add(t2);
set.add(t3);

System.out.println("set size: " + set.size());

поэтому в этом примере вывод моей консоли:

они равны
установленный размер: 3

Это не имеет никакого смысла для меня.. размер должен быть 2?

4b9b3361

Ответ 1

Проблема заключается в том, что ваш класс Element не переопределил методы equals и hashCode, или эти реализации не работают.

Из Object#equals метод javadoc:

Метод equals реализует отношение эквивалентности для ненулевых ссылок на объекты:

  • Это рефлексивно: для любого ненулевого опорного значения х, x.equals(х) должна возвращать истинное.
  • Он симметричен: для любых непустых опорных значений x и y x.equals(y) должен возвращать true тогда и только тогда, когда y.equals(x) возвращает true.
  • Это транзитивно: для любых непустых опорных значений x, y и z, если x.equals(y) возвращает true, а y.equals(z) возвращает true, тогда x.equals(z) должен возвращать true, Это согласовано: для любых непустых опорных значений x и y несколько вызовов -x.equals(y) последовательно возвращают true или последовательно возвращают false, если информация, используемая при равных сравнениях с объектами, не изменяется.
  • Для любого ненулевого опорного значения х, x.equals(NULL) должен возвращать ложь.

Из Object#hashCode метод javadoc:

Общий контракт hashCode:

  • Всякий раз, когда он вызывается одним и тем же объектом более одного раза во время выполнения приложения Java, метод hashCode должен последовательно возвращать одно и то же целое число, если информация, используемая при равных сравнениях с объектом, не изменяется. Это целое число не должно оставаться согласованным с одним исполнением приложения на другое выполнение того же приложения.
  • Если два объекта равны в соответствии с методом equals (Object), то вызов метода hashCode для каждого из двух объектов должен приводить к одному и тому же целочисленному результату.
  • Не требуется, чтобы, если два объекта неравны в соответствии с методом equals (java.lang.Object), то вызов метода hashCode для каждого из двух объектов должен производить различные целочисленные результаты. Тем не менее, программист должен знать, что получение отдельных целых результатов для неравных объектов может улучшить производительность хеш-таблиц.

Убедитесь, что реализации этих методов соответствуют этим правилам, а ваш Set (подкрепленный HashSet) будет работать, как ожидалось.

Ответ 2

У ваших объектов разные хэши, поэтому HashSet "помещает" в разные "ведра".

Ответ 3

Если у вас есть собственные классы моделей, вам нужно изменить некоторые основные функции, как это сделано в приведенном ниже примере.

Код выполнения:

HashSet<MyModel> models = new HashSet<MyModel>();

for (int i = 1; i < 5; i++)
    models.add(new MyModel(i + "", "Name :" + i + ""));

for (int i = 3; i < 5; i++)
    models.add(new MyModel(i + "", "Name :" + i + ""));

for (Object object : models)
    System.out.println(object);

Класс модели:

/**
 * Created by Arun
 */
public static class MyModel {

    private String id = "";
    private String name = "";

    public MyModel(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return getId();
    }

    @Override
    public boolean equals(Object obj) {
        return !super.equals(obj);
    }

    public int hashCode() {
        return getId().hashCode();
    }

}

Надеюсь, что это поможет.

Ответ 4

Да Мы можем реализовать его с объектом классов, которые не являются FINAL.

HashSet Проверяет два метода hashCode() и equals() перед добавлением любого объекта. Сначала он проверяет метод hashCode(), если он возвращает хэш-код, который тот же с любым объектом в Set, затем проверяет метод equals для этого объекта, который внутренне сравнивает ссылки для оба объекта, т.е. this.obj1==obj. Если это те же ссылки, в этом случае он возвращает true, это означает, что это дублирующее значение. Мы можем добавить дублирующие не конечные объекты, переопределив метод HashCode и equals. В HashCode() вы можете вернуть один и тот же хэш-код в случае одинаковых параметров.

См. пример:

public class Product {
int i;
Product(int a)
{
    this.i=a;
}
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + i;
    return result;
}
@Override
public boolean equals(Object obj) {
    /*if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Product other = (Product) obj;
    if (i != other.i)
        return false;
    return true;*/
    return true;
}
}
`

`
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
    Product p1=new Product(1);
    Product p2=new Product(1);
    Product p3=new Product(1);
    Set s=new HashSet();
    s.add(p1);
    s.add(p2);
    s.add(p3);
    System.out.println(s.size());
}
}

Выход будет 1.

P.S: Без переопределения этих методов вывод будет 3, так как он будет использовать свое поведение по умолчанию.