有人可以阐明与班级compareTo()
不一致时的后果是什么。equals()
我已经读过,如果Obj1.compareTo(Obj2) = 0
那么它不是强制性的Obj1.equals(Obj2) = true
。但如果发生这种情况,后果是什么。谢谢。
3 回答
的文档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)
false
a
b
几乎所有实现
Comparable
的 Java 核心类都具有与equals
. 一个例外是java.math.BigDecimal
,其自然排序等同于BigDecimal
具有相同值和不同精度的对象(例如4.0
和4.00
)。
尽管文档说一致性不是强制性的,但最好始终确保这种一致性,因为您永远不知道您的对象是否有一天会出现在TreeMap
/TreeSet
或类似的地方。如果compareTo()
为 2 个不相等的对象返回 0,则所有基于树的集合都将被破坏。
例如,想象一个类Query
,实现一个 SQL 查询,有 2 个字段:
- tableList:表列表
- 参考:使用此类查询的程序列表
假设 2 个对象相等,如果它们的 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;
}
这样做似乎没问题,因为相等和排序是在两个单独的字段上完成的,到目前为止一切都很好。
但是,无论何时放入 aTreeSet
或 a 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;
}
一些集合会假设如果两个对象跟随,obj1.compareTo(obj2) = 0
那么obj1.equals(obj2)
也是如此。例如:排序TreeSet
。未能满足此逻辑将导致图标一致的集合。请参阅:
比较器和 equals()。