zoukankan      html  css  js  c++  java
  • 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;
        }
  • 相关阅读:
    043 抖音短视频爬取实战
    048 Python里面yield的实现原理
    047 Python面试知识点小结
    001 Glang实现简单分布式缓存
    046 算法的时间复杂度和空间复杂度计算
    042 使用Python远程监视多个服务器和数据库的状态,python,监控,同步
    041基于python实现jenkins自动发布代码平台
    045 chrome浏览器前端调试技巧
    STL学习
    Asio与Boost.Asio
  • 原文地址:https://www.cnblogs.com/wanhua-wu/p/6429427.html
Copyright © 2011-2022 走看看