集合源码解析:HashMap的底层实现原理(jdk8.0)

JDK8 HashMap底层实现
本文深入解析JDK8中HashMap的底层实现原理,包括其存储结构、内部机制、源码解析,以及如何通过红黑树优化存储效率。

源码解析JDK8.0集合:HashMap底层实现原理


一、HashMap的概述

HashMap是Map接口的实现类,键值对存储(基于哈希表的映射:根据指定的键,可以获取对应

的值),并允许null作为键和值,线程不安全,即方法为非同步方法。这一点jdk7.0 和 jdk8.0没

有区别。

二、HashMap的存储结构
  1. jdk7.0中的HashMap采用数组+链表形式进行存储,但是如果一个数组对应的链表长度过大

    时,通过key进行查询时效率较低;为了提高效率,jdk8.0中HashMap最大的优化亮点就在

    于采用了数组 + 链表 + 红黑树的 存储方式 。

  2. jdk8.0的HashMap 底层结构依然是一个数组(默认长度为16)也称为哈希表,同样的数组元素

    是一个单向的链表,每一个数组存储的元素代表的是每一个链表的头结点;但是当数组中某

    并且一个链表长度>=8,数组的长度不小于 64 时,会将此链表转换为 红黑树的存储方式,

    存储结构如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fyEGNT4Z-1586609662644)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1572421716008.png)]

三、HashMap内部实现原理机制(源码解析)
  1. HashMap的基本元素

    public class HashMap<K,V> extends AbstractMap<K,V>
        implements Map<K,V>, Cloneable, Serializable {
         
         
    	/*
        	默认的初始容量为:16
        	1 << 4 代表将1左移4位:2^4 = 16
        */
        static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
        
    	//最大容量为2^30 = 1024*1024*1024 = 1073741824
        static final int MAXIMUM_CAPACITY = 1 << 30;
    
    	/* 默认的负载因子
        	负载因子表示一个散列空间的使用程度。
        	当向集合容器中添加元素的时候,会判断当前容器的个数:
        	如果当前容器的个数 > 阈(yu)值:即底层数组长度*负载因子
        */
        static final float DEFAULT_LOAD_FACTOR = 0.75f;
        
    	/*新增:
    		如果数组某一个元素中的链表节点数 >= 8时,
    		需要转换为 红黑树形式存储
    	*/
        static final int TREEIFY_THRESHOLD = 8;
    
    	/*新增:
    		如果数值中某一个 元素转换为红黑树存储之后,在之后的操作中
    		检测到节点数 <6 时,则解散红黑树存储,再 转换为 链表形式
    		进行存储
    	*/
        static final int UNTREEIFY_THRESHOLD = 6;
    	
    	/*新增:
    		如果数组某一个元素中的链表节点数 >= 8时,需要转换为
    		红黑树形式存储,但是 同时 需要 还满足此时的数组长度
    		不能不小 64 ,否则也不会转换为 红黑树形式存储
    	*/
    	static final int MIN_TREEIFY_CAPACITY = 64;
    	
    	/*改变:
    		jdk8.0中底层数组类型由 Entry 类型改变为 Node 类型
    		但是 Node 为 Map.Entry接口的实现类
    		(注意:Entry为Map接口中的内部接口)
    	*/
    	transient Node<K,V>[] table;
    
    	// Map集合中键值对的 个数
    	transient int size;
    	
    	// 记录对集合中元素修改的次数
        transient int modCount;
    
        /* 扩容的临界值(阈值),或者所能容纳的key-value对的极限。
           当size>threshold的时候就会扩容
        */
        int threshold;
    
    	// 加载因子
        final float loadFactor;
    

    jdk8.0中HashMap的实现类中字段部分相对于 jdk7.0做出了部分的改变,没有改变的字段不再详细介绍,以下介绍的为改变或是新增的字段:

    (1) TREEIFY_THRESHOLD = 8 和 MIN_TREEIFY_CAPACITY = 64

    ​ 数组中某一个元素对应的链表形式存储 是否需要转换为红黑树进行存储的依据。

    ​ 如果链表长度大于等于 8,同时Node[] table数组长度不小于 64,则将此链表转换为

    ​ 红黑树进行存储 。

    (2) UNTREEIFY_THRESHOLD = 6

    ​ 被转换为红黑树进行存储的 再次 转换为 链表存储的临界值

    (3) Node<K,V>[] table

    ​ Node<K,V>[] table 相当于 jdk7.0 中的Entry[] table,就是HashMap的底层的数组,

    ​ Node中包含了键和值,详见以下源码:

    // 此静态内部类和内部的属性和方法都是包级访问权限
     static class Node<K,V> implements Map.Entry<K,V> {
         
         
         final int hash;
         final K key;
         V value;
         Node<K,V> next;
    
         Node(int hash, K key, V value, Node<K,V> next) {
         
         
             this.hash = hash;
             this.key = key;
             this.value = value;
             this.next = next;
         }
         public final K getKey()        {
         
          return key; }
         public final V getValue()      {
         
          return value; }
         ....

    存储的具体结构如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ehlWRsIZ-1586609662645)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1572492518766.png)]

  2. HashMap中的构造方法相比于 jdk7.0中的HashMap 没有大的变动,不再具体讲解

  3. HashMap中存储:put方法的实现

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值