美文网首页
HashMap 源码问答

HashMap 源码问答

作者: 天高s | 来源:发表于2020-04-01 22:20 被阅读0次
  • 问题一:HashMap 初始化分配内存了吗?
  • 问题二:HashMap 什么时候分配的内存?第一次分配了多少?
  • 问题三:什么时候触发 rehash ?
  • 问题四:loadFactor 有什么作用?

环境

╰─$ java -version                                                                                                                                                                                         255 ↵
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)

源码解答

问题一

构造函数里没有分配底层存储,只是计算了阈值

    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;
        this.threshold = tableSizeFor(initialCapacity);
    }

loadFactor 默认 0.75
实测 tableSizeFor(100) = 128 tableSizeFor(1000) = 1024 tableSizeFor(4097)=8192

问题二

在第一次 put 的时候检查table == null,调用 resize() 分配内存, 源码中第 628 行

        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;

第一次初始化的容量赋值在 694 行

            newCap = DEFAULT_INITIAL_CAPACITY;  //16

实际分配在 704

            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];

问题三

put(k, v) 的最后会检查阈值,如果超过 threshold 就进行 resize(), 662 行

        if (++size > threshold)
            resize();

在第 687 行赋值新容量, 扩大一倍,容量值最大不会超过 2 的 30 次方

            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold

接着就是 rehash 的详细过程~

问题四

先看变量定义, 这是一个 final 变量, 初始化后就不会变了

    /**
     * The load factor for the hash table.
     *
     * @serial
     */
    final float loadFactor;

第一个找到的地方在 putMapEntries 方法里, 第 504 行

                float ft = ((float)s / loadFactor) + 1.0F;

s 变量是 putMapEntries 方法参数 Map<? extends K, ? extends V> msize(),

putMapEntriesCallHis
四个地方被调用,差不多都是 putAll 的作用

刷新阈值 threshold, 看完理解下来意思是新 mapsize() 除以 loadFactor 再加 1 , 如果比 threshold 大就更新 threshold,加大后的值是一个 2 的 n 次方

第二次使用的地方在 698 行

            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);

作用依然是刷新阈值, 新阈值 threshold 等于 新容量 newCap 乘以 loadFactor, 阈值起作用的地方参看问题三

相关文章

  • HashMap 源码问答

    问题一:HashMap 初始化分配内存了吗? 问题二:HashMap 什么时候分配的内存?第一次分配了多少? 问题...

  • HashMap剖析

    Java集合:HashMap源码剖析 一、HashMap概述 二、HashMap的数据结构 三、HashMap源码...

  • HashMap源码

    HashMap的源码,基于jdk1.7Map的源码 AbstractMap的源码 HashMap的源码

  • HashMap源码笔记(二)

    紧接这上一篇:HashMap源码笔记(一)我们继续来分析HashMap源码,接下来我们来看看HashMap的源码说...

  • 面试准备

    1.HashMap && CurrentHashMap源码分析 HashMap源码解析 java 并发编程之 Co...

  • java源码分析之LinkedHashMap

    相关文章java源码分析之HashMap(一)java源码分析之HashMap(二)java源码分析之HashMa...

  • HashMap原理以及ConcurrentHashMap

    一、HashMap的关键参数及部分源码解析 1.1 HashMap的几个关键参数 HashMap的源码中存下以下几...

  • 【16】 hashmap

    hashmap 1.7 和1.8的区别 hashmap全家桶 hashmap 源码解析 hashmap hashm...

  • JAVA 8 HashMap 源码分析

    JAVA 8 HashMap 源码分析 一 什么是HashMap? HashMap 继承了AbstractMap,...

  • JDK1.8HashMap源码分析

    HashMap源码分析 分析源码之前,先了解一下HashMap的结构,JDK1.7之前HashMap是通过数组结构...

网友评论

      本文标题:HashMap 源码问答

      本文链接:https://www.haomeiwen.com/subject/czyzuhtx.html