The hashCode() and equals() methods must be overridden for the custom (you created) object to determine the behavior when comparing these two objects. Those. It is necessary to explicitly indicate what should be considered identical objects.
The essence of Set'a (set) is that you cannot add objects to it that already exist in it. Those. if you add the same object each time (based on equals and hashCode) it will not be added. Using the implementation of LinkedHashSet already implies storing in the order of addition.
Suppose I have a class:
class MyClass{ private int id; private String name; public MyClass(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public String getName() { return name; } }
Now I create a Set and place two objects in it:
Set<MyClass> set = new LinkedHashSet<>(); set.add(new MyClass(1,"1")); set.add(new MyClass(1,"1")); set.forEach(myClass -> System.out.println("Element -> id: "+myClass.getId()+"; name: "+myClass.getName()));
Result:
Element -> id: 1; name: 1
Element -> id: 1; name: 1
Those. There are two objects in the current set. This happens because all objects in Java are inherited from the Object class, in which objects are compared by reference (to a section in memory). Those. technically, these are two different objects (located in different parts of the memory), and they are not equal.
That is why it is necessary to explicitly override the equals () and hashCode () methods, since they should describe the logic of comparing two different objects.
Add these methods to the MyClass class:
@Override public boolean equals(Object o) { //Здесь явное сравнение по ссылке if (this == o) return true; //Здесь, если объект не является таким же классом то вернет false if (!(o instanceof MyClass)) return false; MyClass myClass = (MyClass) o; //Здесь, если id'шники не равны вернет false if (getId() != myClass.getId()) return false; //Здесь, если name не равен null (у того и другого объекта) и они идентичны возвращаем true return getName() != null ? getName().equals(myClass.getName()) : myClass.getName() == null; } @Override public int hashCode() { //Здесь складываем значения id и hashCode() строки name и получаем относительно уникальный хэш int result = getId(); result = 31 * result + (getName() != null ? getName().hashCode() : 0); return result; }
I will rerun the creation code Set'a just add a couple of elements:
Set<MyClass> set = new LinkedHashSet<>(); set.add(new MyClass(1,"1")); set.add(new MyClass(2,"2")); set.add(new MyClass(2,"not 2"));//Id совпадают, но name разные set.add(new MyClass(1,"1"));//Пытаюсь добавить уже существующий элемент set.add(new MyClass(3,"3")); set.add(new MyClass(2,"2"));//Пытаюсь добавить уже существующий элемент set.forEach(myClass -> System.out.println("Element -> id: "+myClass.getId()+"; name: "+myClass.getName()));
Result:
Element -> id: 1; name: 1
Element -> id: 2; name: 2
Element -> id: 2; name: not 2
Element -> id: 3; name: 3
As can be seen from the example, identical values were not added, although at the same time these are different objects in memory. According to this logic, I can refuse to compare the name field, then it will occur only by id.
PS For most classes built into Java, these methods are already defined, and you do not need to do this explicitly.