Effective Java 第9条: 覆盖 equals 时总
2019-01-03 本文已影响0人
linyk3
在每个覆盖了equals 方法的类中,也必须覆盖 hashCode 方法.
否则违反Object.hashCode 通用规定,从而导致无法结合所有基于散列的集合一起正常运作.
Object.hashCode 约定的内容:
- 在应用程序执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么多次调用hashCode方法都必须始终如一的返回同一个整数. 同一个程序被多次执行过程中, hashCode返回的整数可以不一致.
- 如果 x.equals(y) == true 那么要求 x.hashCode() == y.hashCode()
- 如果 x.equals(y) == false, 没有要求 x.hashCode != y.hashCode, 但是不同对象产生不同的hashCode有利于hash tables 的性能.
一个好的散列函数通常倾向于:为不相等的对象产生不相等的散列码.
简单的hash方法:
- int result = 17 (要求非0的整数即可)
- 对于对象中的每个关键域f(也就是 equals 中涉及的每个域),
- 2.1 计算该域的散列码 c:
- i. boolean 类型: c = (f ? 1:0)
- ii. byte,char,shot,int类型, c = int(f)
- iii. longs类型: c = (int)(f ^ (f >> 32))
- iv. float类型: c = Float.floatToIntBits(f)
- v. double类型: fb = Double.doubleToLongBits(f), c = (int)(fb ^ ( fb >> 32))
- vi. 对象引用类型: c = (f = null ? 0: f.hashCode())
- vii. 数组类型: c = Arrays.hashCode()- 2.2 rerult = 31 * result + c (使用奇素数31,防止乘法溢出, 并且 31 * i = (i << 5) - i)
- 2.1 计算该域的散列码 c:
- 对于对象中的每个关键域f(也就是 equals 中涉及的每个域),
- return result
- 检查是否满足相等的实例具有相等的散列码.
缓存hashCode,并延迟初始化:
private volatile int hashCode;
// equals 方法比较涉及的三个域: short areaCode, short prefix, short lineNumber
@Override
public int hashCode() {
int result = hashCode;
if (result == null) {
result = 17;
result = 31 * result * areaCode;
result = 31 * result * prefix;
result = 31 * result * lineNumber;
hashCode = result;
}
return result;
}
**不要试图从散列码计算中排除一个对象的关键部分来提高性能.这样虽然计算hashCode可能会快一点,但是hash表不一定好.