• Map接口的实现类---HashMap


    HashMap

    类定义

    public class HashMap extends AbstractMap
            implements Map, Cloneable, Serializable
            
            注意:Map接口的定义
                   public interface Map 没有父接口

    具体的内部数据存储方式

    transient Node[] table; //哈希表的本质是一个数组,数组中每一个元素称为一个桶,桶中存放的是键值对
     

    transient Set> entrySet;并不是用于实际存储数据,主要用于针对entrySet和keySet两个视图提供支持

    transient int size;当前集合中的元素个数
     
    final float loadFactor;  当前集合的负载因子,当前Map集合中扩容的阈值【负载因子*最大容积】

    transient int modCount;修改次数,主要用于实现多线程操作时的快死异常

    重要的阈值

    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 默认的初始化容积

    static final int MAXIMUM_CAPACITY = 1 << 30;最大容积值,实际上就是2的30次方

    static final float DEFAULT_LOAD_FACTOR = 0.75f; 默认的负载因子/加载因子

     
    static final int TREEIFY_THRESHOLD = 8;//树化阈值:即链表转成红黑树的阈值,在存储数据时,当链表长度 > 该值时,则将链表转换成红黑树

    static final int MIN_TREEIFY_CAPACITY = 64;//最小树形化容量阈值:即 当哈希表中的容量 > 该值时,才允许树形化链表 (即将链表转换成红黑树)否则,若桶内元素太多时,则直接扩容,而不是树形化

    static final int UNTREEIFY_THRESHOLD = 6;//桶的链表还原阈值:即红黑树转为链表的阈值,当在扩容resize)时(此时HashMap的数据存储位置会重新计算),在重新计算存储位置后,当原有的红黑树内数量< 6时,则将红黑树转换成链表

    内部存储的实现

    静态内部类用于实现Entry,HahMap中存放的key/value对就被封装为Node对象。其中key就是存放的键值,用于决定具体的存放位置;value是具体存放的数据,hash就是当前Node对象的hash值,next用于指向下一个Node节点(单向链表) 
     
    static class Node implements Map.Entry {
            final int hash;  当前节点的hash值
            final K key;   该节点存储的key值
            V value;  该节点存储的value值
            Node next;   下一个节点对象   --- 默认使用单向链表结构,当一个链表上的节点数>8并且总存储元素个数>64时自动转换为红黑树

    构造器

    public HashMap() {
            this.loadFactor = DEFAULT_LOAD_FACTOR; //给属性loadFactor负载因子赋默认值0.75
            //并没有对数组进行初始化操作。采用延迟初始化的策略可以节约空间
        }
        
        //当指定初始化容积时,调用另外的构造器进行HashMap的初始化,采用默认的负载因子0.75
        public HashMap(int initialCapacity) {
            this(initialCapacity, DEFAULT_LOAD_FACTOR);
        }
        
        //2个参数的构造器,参数1初始化容积大小,参数2负载因子
        public HashMap(int initialCapacity, float loadFactor) {
            //对初始化容积值进行合法性验证,如果<0则抛出异常
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
            if (initialCapacity > MAXIMUM_CAPACITY)
                initialCapacity = MAXIMUM_CAPACITY;
                
            if (loadFactor <= 0 || Float.isNaN(loadFactor))  负载因子应该在(0,1]之间的浮点数
                //负载因子越小,哈希碰撞的概率越低,也就意味着链表长度越小,但是浪费空间;如果值越大,则节约空间,但是哈希碰撞概率提高,所以一般建议值在(0,1]之间
                throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
                
            this.loadFactor = loadFactor;   //接收合法的负载因子值
            this.threshold = tableSizeFor(initialCapacity);    并不是直接使用传入的参数作为初始化数组的长度,而是将传入的整数转换大于等于initialCapacity的最小2的n次方值
                例如initialCapacity=5,则真正的初始化容积为8
                initialCapacity=10,则真正的初始化容积为16
            
        }
        
        Float.isNaN判断参数是否为一个不是数值  NaN含义为Not a number
         public static boolean isNaN(float v) {
            return (v != v);
        }
        
        //根据传入的初始化容积值求一个合法的初始化容积值
         static final int tableSizeFor(int cap) {
            int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);
            return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
        }

  • 相关阅读:
    【HDFS】Hadoop-RPC:客户端侧通过Client.Connection#sendRpcRequest方法发送RPC序列化数据
    【2022杭电多校5 1012题 Buy Figurines】STL的运用
    论文翻译:2021_LACOPE: Latency-Constrained Pitch Estimation for Speech Enhancement
    红蓝对抗-红队渗透下的入口权限快速获取
    Jmeter常见压测错误解决
    【论文解读】The Power of Scale for Parameter-Efficient Prompt Tuning
    Visual Studio 2022插件的安装及使用 - 编程手把手系列文章
    canal 设置offset和binlog,POSITION
    综合工具-Design Compiler使用(从RTL到综合出各种报告timing\area\critical_path)
    【Python_Process_Thread】Processing_Threading
  • 原文地址:https://blog.csdn.net/tiger_root/article/details/127045627