equals 方法
Object 类的 equals 方法是比较两个对象的地址是否相等,也就是说所有类的默认 equals 方法都是比较地址是否相等;所以当需要判断复杂对象是否相等时,我们要重写 equals 方法:
//例子
@Override
public final class PhoneNumber{
private short areaCode, prefix, lineNum;
public boolean equals(Object o){
if(o == this)
return true;
if(!(o instanceof PhoneNumber))
return false;
PhoneNumber pn = (PhoneNumber)o;
return pn.lineNum == lineNum && pn.prefix == prefix &&pn.areaCode == areaCode;
}
}
注意:
- 不要将 equals 参数类型 Object 改为其他的类型,否则将重载 (Overload)
Object.equals
而不是覆盖 (Override)Object.equals
; - equals 方法应该满足自反性、对称性、传递性、一致性(如果没有修改,必须保持相等)和非空性(任何对象不能等于 null,
instanceof
关键字可以检查)。
hashCode 方法
哈希码有一个通用约定:
- 一个对象多次调用 hashCode 方法都应该返回相同的值;
- 两个对象通过 equals 方法比较返回 true,则它们的 hashCode 一定相等,也就是说相等的对象必须具有相等的散列码 (hash code);
- 两个对象的 hashCode 相等,那么两个对象不一定相等;
- 一个好的散列函数(hashCode)通常倾向于为不相等的对象产生不相等的散列码,这样可以提高哈希表的性能;
在判断两个对象是否相等时,会先判断 hashCode 是否相等,如果 hashCode 不相等则认为两个对象不相等;如果 hashCode 相等再进行 equals 方法比较;这是因为 hashCode 方法比 equals 方法效率高,当我们要判断 Set 集合是否存在某一个对象时,先定位到 hashCode 对应的哈希桶里寻找,如果没有对象则说明不存在该对象,如果有对象再用 equals 方法判断,大大提高了查找效率;(HashSet 底层是用 HashMap 实现的)
为什么重写 equals 方法时必须重写 hashCode 方法?
Object 类的 equals 方法比较两个对象的地址是否相等,hashCode 方法是一个本地方法,返回一个由对象的地址转换得到的值,所以如果我们重写了 equals 方法,但没有重写 hashCode 方法,这样的话当两个对象通过 equals 比较的结果是相等的,但是因为它们的 hashCode 不同,所以 Java 判断它们是不相等的两个对象,也就可以同时放到 HashSet 中,这就导致了错误的发生;
hashCode 怎么重写?
- 声明一个 int 类型变量 result,初始化为对象中第一个关键域的散列码(关键域指影响 equals 比较的域),按步骤 2.a 中的计算方法;
对剩下的每一个关键域 f 完成以下步骤:
a. 计算该域 int 类型的散列码 c:
- 该域是基本类型,散列码为
Type.hashCode(f)
,Type 为对应的装箱类型; - 该域是对象引用,如果为 null,返回 0,否则调用这个对象的 hashCode 方法;
- 该域是数组类型,对数组的每个重要的元素计算一个散列码然后用 2.b 中的方法组合起来。如果数组中所有元素都重要,可以使用
Arrays.hashCode()
方法。
- 该域是基本类型,散列码为
b. 按照公式将 2.a 中得到的散列码合并到 result 中:
result = 31 * result + c;
例子:
@Override
public int hashCode(){
int result = Short.hashCode(areaCode);
result = 31 * result + Short.hashCode(prefix);
result = 31 * result + Short.hashCode(lineNum);
return result;
}
参考资料:
- hashCode 原理分析
- hashCode 源码
- 「Effective Java 第三版」
- 面试官:为什么重写equals时必须重写hashCode方法?
- Java equals方法详解
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。