为什么HashMap.put比较哈希和测试相等?

我用Java分析HashMap源代码并得到关于put方法的问题。

下面是JDK1.6中的put方法:

 public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entry e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; } 

我对if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

为什么这样的情况?

因为在Java超类Object ,有一个hashCodeequals的契约 :

如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须生成相同的整数结果。

所以key.equals(k)意味着key.hashCode() == k.hashCode()

hash()如下:

  static int hash(int h) { // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } 

因此key.hashCode() == k.hashCode()意味着e.hash == hash

那么为什么不是if ((k = e.key) == key || key.equals(k))

这只是一个优化:比较两个整数比调用equals()更快。

如果两个哈希码不同,那么,基于equalshashCode的契约,地图知道现有密钥不等于给定密钥,并且可以更快地到达下一个密钥。

它只是避免了方法调用:如果散列(不是hashCode() ,它是地图自己的散列)与条目的散列不同,它知道它根本不必调用equals 。 只是优化了一下。

‘hash’变量的值可以与keys hashcode不同。 ‘hash’变量是调用’hash(key.hashCode())’方法的结果。 因此,需要比较哈希值和键的相等性。