• [Java] HashMap 源码简要分析


     特性

    * 允许null作为key/value。
    * 不保证按照插入的顺序输出。使用hash构造的映射一般来讲是无序的。
    * 非线程安全。
    * 内部原理与Hashtable类似。
     
    源码简要分析
    public class HashMap<K,V>
    {
         static final int DEFAULT_INITIAL_CAPACITY = 16 ; // 默认初始容量是16。(必须是2的次方)
         static final int MAXIMUM_CAPACITY = 1 << 30 ; // 即2的30次方
         static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认装载因子
    
         Entry[] table;  // Entry表
         int size; // Entry[]实际存储的Entry个数
         int threshold; // reash的阈值,=capacity * load factor
         final float loadFactor;
    
         // 构造函数
         public HashMap(int initialCapacity, float loadFactor) {
         // 找到一个比initialCapacity大的最小的2的次方数
         int capacity = 1;
         while (capacity < initialCapacity)
                capacity <<= 1;
         }
    
         this.loadFactor = loadFactor;
         threshold = (int)(capacity * loadFactor);
         table = new Entry[capacity];
    
         // addEntry()
        void addEntry(int hash, K key, V value, int bucketIndex) {
            Entry<K,V> e = table[bucketIndex];
            table[bucketIndex] = new Entry<>(hash, key, value, e);
            if (size++ >= threshold)
                resize(2 * table.length);
        }
    
         // put():添加元素
         public V put(K key, V value) {
              int hash = hash(key.hashCode());     // key的hash值
              int i = indexFor(hash,table.length);     // 槽位
    
              // 寻找是否已经有key存在,如果已经存在,使用新值覆盖旧值,返回旧值
              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;
                    return oldValue;
                }
              }
    
              // 添加Entry
              addEntry(hash,key,value,i);
              return null;
         }
    
         // resize():重新哈希
        void resize(int newCapacity) {
            Entry[] oldTable = table;
            int oldCapacity = oldTable.length;
            Entry[] newTable = new Entry[newCapacity];
            transfer(newTable);
            table = newTable;
            threshold = (int)(newCapacity * loadFactor);
        }
    
        /**
         * Transfers all entries from current table to newTable.
         */
        void transfer(Entry[] newTable) {
            Entry[] src = table;
            int newCapacity = newTable.length;
            for (int j = 0; j < src.length; j++) {
                Entry<K,V> e = src[j];
                if (e != null) {
                    src[j] = null;     
                    do {
                        Entry<K,V> next = e.next;
                        int i = indexFor(e.hash, newCapacity);
                        e.next = newTable[i];
                        newTable[i] = e;
                        e = next;
                    } while (e != null);
                }
            }
        }
    
    }
    

      

    遍历方式

    * 低效遍历:按照Key进行遍历,则每次都需要按Key查找槽位(不同的Key有重复查找),且可能需要遍历槽位上所在Entry链表(不同的Key有重复遍历)。
    * 高效遍历:HashMap的entrySet()返回自定义的EntryIterator,是先按照槽位遍历一次,再遍历一次槽位上Entry链表。
    Map<String, String[]> paraMap = new HashMap<String, String[]>();
    for( Map.Entry<String, String[]> entry : paraMap.entrySet() )
    {
        String appFieldDefId = entry.getKey();
        String[] values = entry.getValue();
    }
    

      

  • 相关阅读:
    js实现考试倒计时
    freemarker常见语法大全
    页面修改图片路径
    freemaker页面字符串特殊字符显示异常处理
    win10家庭版远程连接 要求的函数不受支持
    mysql出现提示错误10061的解决方法
    freemark
    面对众多的前端框架,你该如何学习?
    HBase 入门
    Hive 优化
  • 原文地址:https://www.cnblogs.com/caca/p/java_hashmap.html
Copyright © 2020-2023  润新知