【Java Collections】Map-HashMap 源码解析(二)

HashMap 内的主要数据结构

  1. 内部类 Node<K,V>(实现了Map.entry接口,存储key-value的基础类,链表)
  2. table (Node<K,V> 数组)

基本思路是(后续会做更详细的解读):

  1. 根据key的hash值确定table的index索引
  2. table的每个index实际上存储的是Node链表,由第1步确定索引后,再循环链表如果存在相同key(key.equals)则替换Node的value值,否则链表尾添加新Node

构造函数

无参构造函数

threshold 变量为阈值,table大小查过该变量就会触发扩容(resize)
而 threshold = capacity * loadFactor

    public HashMap() {
        // 默认扩容因子0.75
        this.loadFactor = DEFAULT_LOAD_FACTOR; 
    }
    // table 的初始化推迟到了 map.put(key,value) 的resize()时
    newCap = DEFAULT_INITIAL_CAPACITY;
    newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
     /** 省略部分代码 **/
    // 初始化table
    Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    table = newTab;

Map参数构造函数

public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;// 默认扩容因子0.75
        //主要做两件事情
        //1. 利用上一篇文章提到的 求2的幂 的方法,确定HashMap的size
        //2. 将 m 内的key-value(即node)逐个复制到该HashMap中
        putMapEntries(m, false);
    }

初始变量构造函数

public HashMap(int initialCapacity, float loadFactor) {
        // 参数的合法性校验       
         if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        // threshold 为扩容阈值,超过该值即触发resize
        // tableSizeFor即上篇文章介绍的求2的幂方法
        this.threshold = tableSizeFor(initialCapacity);
    }

// table 的初始化也推迟到了 map.put(key,value) 的resize()时,与无参构造函数不同的是,此处初始化的大小,正是你设置的initialCapacity,而threshold也被重新计算
// 利用threshold做一个存储的过渡,完美做到了一点都不浪费不啰嗦的优良传统
newCap = oldThr;
        if (newThr == 0) {
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        threshold = newThr;
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        table = newTab;

// 阿里开发规约建议使用该 初始化函数,设置初始容量,尽可能的避免map.resize带来的性能消耗,也提高存储空间的利用率(用多少声明多少)
public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

小结

综上可以发现,初始化主要是设置table容量相关值,具体的table大小初始化推迟到了putValue阶段,这也就是下篇文章要介绍的重点。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、基本数据类型 注释 单行注释:// 区域注释:/* */ 文档注释:/** */ 数值 对于byte类型而言...
    龙猫小爷阅读 4,295评论 0 16
  • 中华医学会放射学分会对比剂安全使用工作组 01碘对比剂分类 目前临床应用的含碘对比剂的基本结构是3一乙酰一2,4,...
    狂奔的蜗牛_9573阅读 6,127评论 0 2
  • 世间至味留遐意,木槿枝头起。秋风飒飒过黄驹,明月几人能共一沟渠。 长空未语笙歌误,冷墨清光住。落花看尽漫相同,从此...
    问字楼阅读 906评论 12 49
  • 大学时逃了很多课,然后去空旷安静的校园里四处游荡。 大部分时候都懒的拍照。眼睛才是最好的相机。但没有用相机和文字记...
    crowforest阅读 375评论 0 0
  • “一个你爱的人和一个爱你的人,你会选择哪一个?” “我会选择成熟的那个。” 昨晚在朋友圈里看到一对相恋六年...
    冯绘新阅读 546评论 0 1