zoukankan      html  css  js  c++  java
  • Java中hashCode()方法以及HashMap()中hash()方法

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

    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()一下。

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

    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/709945

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

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

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

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

  • 相关阅读:
    jQuery入门(8):工具
    jQuery入门(2):核心(核心函数,对象访问,多库共存)
    jQuery入门(6):Ajax
    jQuery入门(7):效果
    jQuery入门(4):CSS相关API
    threadwait/sleep
    【转】Query的extend扩展方法使用点滴
    jquery.query2.1.7.js 操作url
    zhuan
    通用分页存储过程 采用ROW_NUMBER(),支持2005及以后的版本
  • 原文地址:https://www.cnblogs.com/tonyluis/p/5671873.html
Copyright © 2011-2022 走看看