HashMap实现原理

HashMap实现原理(JDK版本:1.7.0_80)

     Map<String, String> sMap = new HashMap<String, String>();             // 1.初始化
        sMap.put("1", "子");                                                  // 2.put操作
        sMap.put("2", "丑");
        sMap.put("3", "寅");
        sMap.put("4", "卯");
        
        String name = sMap.get("1");                                          // 3.get操作

        for(Entry<String, String> entr : sMap.entrySet()){
            System.out.println(entr.getKey() + ":" + entr.getValue());
        }

1,初始化

类加载:

ClassLoader.loadClass(String name)

ClassLoader.checkPackageAccess(Class cls, ProtectionDomain pd)

HashMap初始化:

HashMap();     DEFAULT_INITIAL_CAPACITY=16 (容量)    DEFAULT_LOAD_FACTOR=0.75 (负载因子)

2,put操作

HashMap的put操作:

  public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);                                                       //1.根据key计算hashCode
        int i = indexFor(hash, table.length);                                       //2.根据hashCode和哈希表大小计算下标   
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {                      //3.根据下标和hashCode,key查询key是否已存在,若存在更新value
            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);                                              //4.key不存在,将新的键值对存入HashMap
        return null;
    }

HashCode计算:

  final int hash(Object k) {     //使用key计算hashCode
        int h = hashSeed;
        if (0 != h && k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }

        h ^= k.hashCode();

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

位运算:

h                            1111 1111 1111 1111    1111 0000 1110 1010

h >>> 16                0000 0000 0000 0000    1111 1111 1111 1111

h ^ (h >>> 16)        1111 1111 1111 1111    0000 1111 0001 0101

 

HashMap存储下标计算:

  static int indexFor(int h, int length) {   //HashCode和哈希表大小
        // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
        return h & (length-1);
  }

键值存储:

  void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {       //threshold = 容量 * 负载因子     size = HashMap当前大小
            resize(2 * table.length);                                    //若当前HashMap大小>=threshold时,进行resize操作,大小为当前2倍
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }

        createEntry(hash, key, value, bucketIndex);
    }

  void createEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        size++;
    }

 

Resize操作:
  void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }

        Entry[] newTable = new Entry[newCapacity];
        transfer(newTable, initHashSeedAsNeeded(newCapacity));                               //将原来HashMap的内容移植到新HashMap中
        table = newTable;
        threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
    }
void transfer(Entry[] newTable, boolean rehash) {
        int newCapacity = newTable.length;
        for (Entry<K,V> e : table) {
            while(null != e) {
                Entry<K,V> next = e.next;
                if (rehash) {                                                               //是否重新计算HashCode,只要resize该值应该为true
                    e.hash = null == e.key ? 0 : hash(e.key);                               //1.重新根据key计算HashCode
                }
                int i = indexFor(e.hash, newCapacity);                                      //2.根据HashCode和哈希表大小计算下标
                e.next = newTable[i];
                newTable[i] = e;                                                            //3.将原来键值的存储地址指向新哈希表
                e = next;
            }
        }
    }

 

 

 3,get操作

  public V get(Object key) {
        if (key == null)
            return getForNullKey();
        Entry<K,V> entry = getEntry(key);

        return null == entry ? null : entry.getValue();
    }
  final Entry<K,V> getEntry(Object key) {
        if (size == 0) {
            return null;
        }

        int hash = (key == null) ? 0 : hash(key);                                     //1.根据key计算HashCode
        for (Entry<K,V> e = table[indexFor(hash, table.length)];                      //2.根据下标和hashCode,key在HashMap中查询key对应的value 
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        return null;
    }

 

posted @ 2017-02-22 16:07  wanhua.wu  阅读(200)  评论(0编辑  收藏  举报