可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a custom class like Person:
public class Person { int age; String name; }
Now I want to sort Person
class objects based on age
.
So I will use Comparable
interface and implement compareTo()
method.
And compareTo
will have logic to compare person object based on just age
.
So if I do :
Collections.sort(list); // where list is a list of person
I will get sorted person list based on age
.
But I read somewhere, we need to override equals()
method as well when we do Comparable
implementation.
But I am not seeing its use as of now.
Can anyone explain, where there will be a need to override equals()
method as well if I want to just sort
based on age
?
回答1:
There is no law that relates Comparable.compareTo()
and equals()
. However I'd say that it is confusing if compaeTo()
returns 0
while equals()
returns false
.
I think that in your case you should use custom comparator instead of making your class Comparable
. The reason is that today your comparison criteria is age, tomorrow it will be the person's first name, then last name, then weight... etc, etc. This is the reason that Comparator
was introduced and the use case when it should be used.
回答2:
From the javadoc for Comparable
:
It is strongly recommended (though not required) that natural orderings [i.e. the ordering defined by Comparable.compareTo
] 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. In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of the equals method.
"Consistent with equals" means that compareTo
returns 0 if and only if equals
returns true
. So unless compareTo
always returns a value != 0
for two different object references, equals
should be overridden.
回答3:
You don't need to override equals, since Collections.sort()
will use compareTo()
, not equals()
. However, it's generally a good idea to override it.
回答4:
Just to elaborate more on this why compareTo() and equals() need to be consistent. The Sorted Set depends on the Object's compareTo() method to know whether a particular element can be added or not in the set and to avoid duplicate elements from being added into the set. So if this is the case , then it leads to ambiguity(copied from the specs):-
For example, if one adds two keys a and b such that (!a.equals(b) && a.compareTo(b) == 0) to a sorted set that does not use an explicit comparator, the second add operation returns false (and the size of the sorted set does not increase) because a and b are equivalent from the sorted set's perspective.
To elaborate more, sorted set used compareTo() to check if the two elements a & b are equal or not and if the Class for a & b only overrides compareTo() method and not equals() method , then we could have a scenario where compareTo() method returns 0, but equals() method return false, which is quite weird and inconsistent. Let's say I have a Name class as shown below:-
public class Name implements Comparable<Name> { private final String firstName, lastName; public Name(String firstName, String lastName) { if (firstName == null || lastName == null) throw new NullPointerException(); this.firstName = firstName; this.lastName = lastName; } public String firstName() { return firstName; } public String lastName() { return lastName; } /*public boolean equals(Object o) { if (!(o instanceof Name)) return false; Name n = (Name) o; return n.firstName.equals(firstName) && n.lastName.equals(lastName); } public int hashCode() { return 31 * firstName.hashCode() + lastName.hashCode(); }*/ public String toString() { return firstName + " " + lastName; } public int compareTo(Name n) { int lastCmp = n.lastName.compareTo(lastName); return (lastCmp != 0 ? lastCmp : n.firstName.compareTo(firstName)); }
}
// Tester class main method has the below code Name n1 = new Name("John", "Smith"); Name n2 = new Name("John", "Smith"); SortedSet<Name> mySet = new TreeSet<>(); System.out.println(mySet.add(n1)); System.out.println(n1.equals(n2)); System.out.println(n1.compareTo(n2)); System.out.println(mySet.add(n2));
The output is as shown below:-
true false 0 false
Now this shows the ambiguity since we haven't overridden the equals() which in this case is returning false, but compareTo() is returning 0 and hence SortedSet considers the two objects n1 and n2 equal and hence adding n2 into the Set return false as shown in the sysout but they are not equal!!!
For more please refer to the stackoverflow link:-Comparator and equals()