Java equals compareTo()的区别
看JDK
源代码尤其是集合框架源代码的时候,经常会看见两个方法:
int equals(Object obj);
int compareTo(Object obj);
在集合框架中大多数集合类是采用equals
方法来对key
进行区分的,例如HashMap
、LinkedHashMap
、HashSet
、LinkedHashSet
等等;
而有些集合类是采用compareTo
方法来对key
进行区分的,例如TreeMap
、TreeSet
等,这一类集合的key
通常是具有顺序性的,都直接或间接的实现了 SortedMap
或SortedSet
接口。
对于compareTo
方法,它是接口Comparable
接口的一个方法;除此之外,还有另一个接口Comparator
,里面含有一个方法compare(T a, T b)
;
而对于equals
方法,是属于顶级类Object
类的一个方法,查看Object
的源代码便可以发现:
public boolean equals(Object obj) {
return (this == obj);
}
对于上述提及的equals
、Comparable
的compareTo
方法、Comparator
的compare(T a, T b)
方法:
方法 | 说明 |
---|---|
a.equals(b) | 比较 对象a 与b 是否逻辑相等(可以是== 比较),但是也可以重写自定义相等的含义 |
a == b | 操作符,比较俩引用引用的对象是否物理上是同一个对象 |
a.compareTo(b) | 比较对象a 与b 的自然顺序 |
compare(a, b) | 同a.compareTo(b) |
需要补充说明的是:
compareTo()
方法属于接口Comparable
,因此不是所有的类都拥有该方法,因为有些类根本不具有比较大小的属性;compareTo()
的参数不能为null
;而equals()
的参数可以是null
,返回值false
;- 在实现
Comparable
接口的compareTo
方法时,强烈推荐与equals
的结果一致,否则可能会出现一些奇怪的错误;因为有些类是利用equals
来判断重复性,
而有些类是利用自然顺序x.compareTo(y) == 0
来判断,官方文档强烈推荐:(x.compareTo(y)==0) == (x.equals(y))
;
举两个例子,HashMap
的put
方法中有如下代码:
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//先用==比较,然后再用equals比较
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
而在TreeMap
的put
方法中有如下代码:
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);//通过compareTo方法来比较
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
文档中关于这个给了一些说明:
Virtually all Java core classes that implement Comparable have natural orderings that are consistent with equals.
One exception is java.math.BigDecimal, whose natural ordering equates BigDecimal objects with equal values and different precisions (such as 4.0 and 4.00).
java
中大部分类都保持了equals
和compareTo
的一致性,但有一个反例就是BigDecimal
。