当compareTo()
与某个类的equals()
不一致时,有人可以说明后果是什么。我已经读过,如果Obj1.compareTo(Obj2) = 0
那么Obj1.equals(Obj2) = true
并非强制要求。但如果发生这种情况会有什么后果。感谢。
答案 0 :(得分:11)
Comparable
的文档详细说明了这一点:
类
C
的自然顺序与equals
一致,当且仅当e1.compareTo(e2) == 0
与e1.equals(e2)
具有相同的布尔值时才e1
类e2
的{}和C
。请注意,null
不是任何类的实例,即使e.compareTo(null)
返回NullPointerException
,e.equals(null)
也应该抛出false
。强烈建议(尽管不要求)自然排序与
equals
一致。这是因为没有显式比较器的有序集(和有序映射)在与自然排序与equals
不一致的元素(或键)一起使用时表现得“奇怪”。特别是,这样的有序集(或有序映射)违反了集合(或映射)的一般契约,它是根据equals
方法定义的。例如,如果将
a
和b
两个键(!a.equals(b) && a.compareTo(b) == 0)
添加到不使用显式比较器的有序集合中,则第二个添加操作将返回{{1} (并且有序集的大小不会增加)因为false
和a
从排序集的角度来看是等效的。实际上,所有实现
b
的Java核心类都具有与Comparable
一致的自然排序。一个例外是equals
,其自然排序等同java.math.BigDecimal
个对象具有相同的值和不同的精度(例如BigDecimal
和4.0
)。
答案 1 :(得分:3)
虽然文档说一致性不是强制性的,但最好始终确保这种一致性,因为您永远不知道您的对象是否有一天出现在TreeMap
/ TreeSet
之类的。如果compareTo()
对于不相等的2个对象返回0,则所有基于树的集合都将被破坏。
例如,想象一个类Query
,实现一个SQL查询,有两个字段:
假设两个对象相等,如果它们的tableList相等,即tableList
是该对象的自然键。 hashCode()
和equals()
仅考虑字段tableList
:
public class Query implements Comparable {
List<String> tableList;
List<String> references;
Query(List<String> tableList, List<String> references) {
this.tableList = tableList;
this.references = references;
Collections.sort(tableList); // normalize
}
@Override
public int hashCode() {
int hash = 5;
hash = 53 * hash + Objects.hashCode(this.tableList);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Query other = (Query) obj;
return Objects.equals(this.tableList, other.tableList);
}
}
假设我们希望排序与引用数一致。
天真地编写代码会产生compareTo()
方法,如下所示:
public int compareTo(Object o) {
Query other = (Query) o;
int s1 = references.size();
int s2 = other.references.size();
if (s1 == s2) {
return 0;
}
return s1 - s2;
}
这样做似乎没问题,因为在两个单独的字段上完成了相等和排序,到目前为止一直很好。
但是,每当放入TreeSet
或TreeMap
时,都是灾难性的:这些类的实现认为如果compareTo返回0,那么元素是相等的。在这种情况下,这意味着具有相同引用数的每个对象确实是“相等”的对象,显然不是这种情况。
更好的compareTo()
方法可能是:
public int compareTo(Object o) {
Query other = (Query) o;
// important to match equals!!!
if (this.equals(other)) {
return 0;
}
int s1 = references.size();
int s2 = other.references.size();
if (s1 == s2) {
return -1; // not 0, they are NOT equal!
}
return s1 - s2;
}
答案 2 :(得分:0)
有些集合会假设如果两个对象跟随obj1.compareTo(obj2) = 0
,那么obj1.equals(obj2)
也是如此。例如:已排序TreeSet
。
如果不符合此逻辑,将导致图标集合。看到:
Comparator and equals()