I have the follwing Person Class -
Person.java
-
public class Person implements Comparable<Person> {
private int id;
private String name;
Person(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Person: Id = " + id + ", Name = " + name;
}
@Override
public int compareTo(Person person) {
int myReturn = 0;
int minLength = 0;
int i = 0;
boolean equal = false;
if (id > person.id) {
myReturn = 1;
} else if (id < person.id) {
myReturn = -1;
} else {
if (name.length() > person.name.length()) {
minLength = person.name.length();
} else if (name.length() < person.name.length()) {
minLength = name.length();
} else {
equal = true;
minLength = name.length();
}
for (i = 0; i < minLength; i++) {
if (name.charAt(i) > person.name.charAt(i)) {
myReturn = 1;
break;
} else if (name.charAt(i) < person.name.charAt(i)) {
myReturn = -1;
break;
} else {
continue;
}
}
if (i == minLength) {
if (equal) {
myReturn = 0;
} else if (name.length() > person.name.length()) {
myReturn = 1;
} else {
myReturn = -1;
}
}
}
return myReturn;
}
}
Now, I have the following TreeClass instance -
TreeSet<Person> treeSet = new TreeSet<>(List.of(
new Person(4, "Amrita"),
new Person(4, "Amrita"),
new Person(9, "Sunita"),
new Person(12, "Nisha"),
new Person(9, "Sunit"),
new Person(9, "Sunitaa")
));
Upon printing -
Person: Id = 4, Name = Amrita
Person: Id = 9, Name = Sunit
Person: Id = 9, Name = Sunita
Person: Id = 9, Name = Sunitaa
Person: Id = 12, Name = Nisha
So clearly, the two Person instances - new Person(4, "Amrita")
and new Person(4, "Amrita")
are equal.
Now, I have the following Queue code. Since, Queue is a subinterface of Collection interface it implements all methods of Collection interface. So -
Queue<Person> queue3 = new LinkedList<>(List.of(
new Person(4, "Amrita"),
new Person(2, "Suhana"),
new Person(7, "Neha")
));
Person person1 = new Person(4, "Amrita");
Person person2 = new Person(9, "Sunita");
System.out.println(queue3.contains(person1));
System.out.println(queue3.contains(person2));
Ouput -
false
false
Thus it says that new Person(4, "Amrita")
element of Queue and Object new Person(4, "Amrita")
are unequal.
How is this possible?
You need to override @equals
and @hashCode
methods in the class Person
.
Explanation:
You are using TreeSet. If you don't provide an explicit Comparator while creating it, it will use natural ordering (compareTo
) for sorting.
Whenever you @override
compareTo()
, it is highly recommended to @overide
@equals
.
From Collections Documentation:
It is strongly recommended (though not required) that natural orderings be consistent with equals. This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent with equals.
To cut the long story short, since you are using TreeSet as well as other collections (List), you need to @override all three - compareTo, equals and hashCode
PS: Whenever you override @equals
- please @override
hashCode
too. See this.
You can generate these methods inside IDE (Intellij / Eclipse/ VsCode etc) automatically. E.g. it would be something like this:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return id == person.id && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}