HashMap源码学习

史上最详细的 JDK 1.8 HashMap 源码解析_程序员囧辉-CSDN博客_hashmap1.8可能是史上最详细的 HashMap 源码解析。https://blog.csdn.net/v123411739/article/details/78996181疫苗:Java HashMap的死循环 | 酷 壳 - CoolShellhttps://coolshell.cn/articles/9606.html什么?HashMap竟然也有懒加载?_小饭饭带你玩waigua的博客-CSDN博客不花时间的导读:这是《好好面试系列》第28篇原创文,该系列主要分享小饭饭面试别人、和被别人面试的经历,该篇文章主要分享HashMap高频面试题,有兴趣的看看,已经知道的可以无视。前几天H同...https://blog.csdn.net/qq_24557827/article/details/119745908Java中HashMap底层实现原理(JDK1.8)源码分析_tuke_tuke的博客-CSDN博客_hashmap底层实现原理这几天学习了HashMap的底层实现,但是发现好几个版本的,代码不一,而且看了Android包的HashMap和JDK中的HashMap的也不是一样,原来他们没有指定JDK版本,很多文章都是旧版本JDK1.6.JDK1.7的。现在我来分析一哈最新的JDK1.8的HashMap及性能优化。在JDK1.6,JDK1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值https://blog.csdn.net/tuke_tuke/article/details/51588156?ops_request_misc=&request_id=&biz_id=102&utm_term=hashmap%E5%BA%95%E5%B1%82%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-3-51588156.nonecase&spm=1018.2226.3001.4187

HashMap1.8扩容总结

    initialCapacity: 刚开始赋值给 threshold ,后来会通过if (oldThr > 0)这个分支 newCap = oldThr (==threshold );将initialCapacity值赋值给newCap,这时候threshold就被更新为 initialCapacity*0.75

HashMap主要有两种构造函数:

下面的代码片段都是resize方法里,计算map大小的代码:

    1>不带initialCapacity

    这种构造函数会设置 

this.loadFactor = DEFAULT_LOAD_FACTOR;

当第一次put或调用resize方法时会进行初始化,直接进下面这个分支:

else {
        // 3.老表的容量为0, 老表的阈值为0,这种情况是没有传初始容量的new方法创建的空表,将阈值和容量设置为默认值
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }

懒加载初始化后,就会直接设置这个map大小为16 Thr为16*loadFactor

2>带initialCapacity

       这时候直接设置Map的的小为initialCapacity  这个initialCapacity处理后,使得其达到2^n后就赋值给threshold,也就是下面的 oldThr > 0

if (oldThr > 0)
        newCap = oldThr; // initial capacity was placed in threshold
// 当传入初始大小时initialCapacity ,走带初始值的构造函数时,这个Map的初始大小被放在
//threshold中,当第一次Put时就会检测到
// 数组大小为0即oldcap=0,而oldThr(threshold)不为空,这时候就知道
// 是传入了初始值的情况,这时候就知道threshold的值就是传入的初始值,这时候会把他传给newCap,
//然后threshold=newCap* 0.75 ,这样当传入初始大小时initialCapacity的初始化完成

    上面两个if分支都是map中tab为null, 即第一次调用put/resize,触发了初始化时机时会走,当初始化过后以后再扩容会直接走这个分支:

tab扩大2倍或直接到达上限

// 1.老表的容量不为0,即老表不为空
    if (oldCap > 0) {
        // 1.1 判断老表的容量是否超过最大容量值:如果超过则将阈值设置为Integer.MAX_VALUE,并直接返回老表,
        // 此时oldCap * 2比Integer.MAX_VALUE大,因此无法进行重新分布,只是单纯的将阈值扩容到最大
        if (oldCap >= MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return oldTab;
        }
        // 1.2 将newCap赋值为oldCap的2倍,如果newCap<最大容量并且oldCap>=16, 则将新阈值设置为原来的两倍
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
            newThr = oldThr << 1; // double threshold
    }

tableForSzie:

HashMap源码注解 之 静态工具方法hash()、tableSizeFor()(四)_程序员-CSDN博客_hashmap tablesizeforhttps://blog.csdn.net/fan2012huan/article/details/51097331?spm=1001.2101.3001.6650.4&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~default-4.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~default-4.no_search_link&utm_relevant_index=6

红黑树 && 2 3 4树

从2-3-4树到红黑树(上) - nullzx - 博客园欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 相关博客: 从2-3-4树到红黑树(中) 从2-3-4树到红黑树(下) 1. 2-3-4https://www.cnblogs.com/nullzx/p/6111175.html 彻底理解红黑树(三)之 删除 - 简书彻底理解红黑树(一)之 二叉搜索树彻底理解红黑树(二)之 插入彻底理解红黑树(三)之 删除 前言 红黑树的删除情况相对插入会复杂一些,这里以个人认为较好理解和记忆的方式进行分...https://www.jianshu.com/p/84416644c080 Red/Black Tree Visualizationhttps://www.cs.usfca.edu/~galles/visualization/RedBlack.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HashMapJava中最常用的哈希表实现之一,它基于哈希表实现了Map接口。以下是HashMap源码的详细解释: HashMap内部是由一个数组和链表组成的,数组的每个元素称为桶,每个桶存储一个链表(可能为空),链表中的每个节点都是一个键值对(key-value pair)。 以下是HashMap的主要属性: ```java transient Node<K,V>[] table; // 存储元素的数组 transient int size; // 元素大小 int threshold; // 扩容阈值 final float loadFactor; // 负载因子 ``` 其中,table是一个transient修饰的Node数组,存储HashMap中的元素;size表示HashMap中元素的个数;threshold表示HashMap的扩容阈值,即当元素个数达到这个值时就需要扩容;loadFactor是负载因子,用于决定HashMap何时需要扩容。 以下是HashMap的主要方法: 1. put(K key, V value) :将指定的键值对添加到HashMap中,如果键已经存在,则更新对应的值。 2. get(Object key):获取指定键对应的值,如果键不存在则返回null。 3. remove(Object key):从HashMap中删除指定的键值对,如果键不存在则返回null。 4. clear():从HashMap中删除所有的键值对。 5. resize():扩容HashMap,将table的大小增加一倍。 6. hash(Object key):计算键的哈希值。 7. getNode(int hash, Object key):获取指定键的节点。 8. putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict):实际执行put操作的方法,会根据指定的参数决定是否更新已有键的值、是否删除过期键等。 HashMap的put方法实现如下: ```java public V put(K key, V value) { // 计算键的哈希值 int hash = hash(key); // 计算键在table数组中的索引 int i = indexFor(hash, table.length); // 遍历桶中的链表,查找指定键 for (Node<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; e.recordAccess(this); return oldValue; } } // 如果指定键不存在,则创建新的节点,并将其添加到桶的链表中 modCount++; addEntry(hash, key, value, i); return null; } ``` 在这个方法中,我们首先计算键的哈希值,然后计算键在table数组中的索引。接着,我们遍历桶中的链表,查找指定键,如果键已经存在,则更新对应的值。否则,我们创建新的节点,并将其添加到桶的链表中。 HashMap的get方法实现如下: ```java public V get(Object key) { // 计算键的哈希值 int hash = hash(key); // 计算键在table数组中的索引 int i = indexFor(hash, table.length); // 遍历桶中的链表,查找指定键 for (Node<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { // 如果找到指定键,则返回其对应的值 return e.value; } } // 如果指定键不存在,则返回null return null; } ``` 在这个方法中,我们首先计算键的哈希值,然后计算键在table数组中的索引。接着,我们遍历桶中的链表,查找指定键,如果找到指定键,则返回其对应的值。 HashMap的remove方法实现如下: ```java public V remove(Object key) { // 计算键的哈希值 int hash = hash(key); // 计算键在table数组中的索引 int i = indexFor(hash, table.length); // 遍历桶中的链表,查找指定键 Node<K,V> prev = table[i]; Node<K,V> e = prev; while (e != null) { Node<K,V> next = e.next; Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { modCount++; size--; if (prev == e) { table[i] = next; } else { prev.next = next; } e.recordRemoval(this); return e.value; } prev = e; e = next; } // 如果指定键不存在,则返回null return null; } ``` 在这个方法中,我们首先计算键的哈希值,然后计算键在table数组中的索引。接着,我们遍历桶中的链表,查找指定键,如果找到指定键,则从链表中删除节点,并返回其对应的值。否则,我们返回null。 以上就是HashMap源码的详细解释。HashMap是一个非常常用且实用的数据结构,它的实现原理也非常值得深入学习和理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值