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 办法详解