Java中hashCode()方法以及HashMap()中hash()方法

Java的Object类中有一个hashCode()方法:java

public final native Class<?> getClass();  
public native int hashCode();  
public boolean equals(Object obj) {  
  return (this == obj);  
}   
public String toString() {  
 return getClass().getName() + "@" +  Integer.toHexString(hashCode());  
} 
hashCode()是一个native方法,意味着方法的实现和硬件平台有关,默认实现和虚拟机有关,对 于有些JVM,hashCode()返回的就是对象的地址,大多时候JVM根据必定的规则将与对象相关的信息(好比对象的存储地址,对象的字段等)映射成一个数值,并返回。
例如:HotSpot JVM中生成hash实现:hotspot/src/share/vm/runtime/synchronizer.cpp
 
在Java中,hashCode()方法的主要做用是为了配合基于散列的集合(HashSet、HashMap)一块儿正常运行。当向集合中插入对象时,调用equals()逐个进行比较,这个方法可行却效率低下。所以,先比较hashCode再调用equals()会快不少。下面这段代码是java.util.HashMap的中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<K,V> 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;
    }

 indexFor()源码以下:数组

static int indexFor(int h, int length) {  
    return h & (length-1);  
} 

由于hashMap要求Entry数组长度必须为2的幂(hashMap默认值为16,hashTable没有这个要求,默认值为11),因此上述代码就是取h的低4位做为Entry数组的下标。由于覆盖equals()须要覆盖hashCode(),因此hashCode()有时并不十分完美,好比只和高位有关等等,所以须要再次hash()一下。app

hash()方法在JDK1.7中以下:this

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);
}

这样设计保证了对象的hashCode的32位值只要有一位发生改变,整个hash()返回值就会改变,高位的变化会反应到低位里。设计

具体分析参考:http://www.iteye.com/topic/709945code

https://www.zhihu.com/question/20733617对象

hash()方法在JDK1.8中以下:blog

static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

 这样设计保证了对象的hashCode的高16位的变化能反应到低16位中,相比较而言减小了过多的位运算,是一种折中的设计。ip

相关文章
相关标签/搜索