HashMap 源码分析

HashMap 在JDK1.8之前呢主要是数组加链表的形式
        在1.8之后是数组+链表+红黑树的形式。
        
        以下为HashMap主要属性:
        public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
            // 序列号
            private static final long serialVersionUID = 362498820763181265L;    
            // 默认的初始容量是16
            static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;   
            // 最大容量
            static final int MAXIMUM_CAPACITY = 1 << 30;
            // 默认的填充因子
            static final float DEFAULT_LOAD_FACTOR = 0.75f;
            // 当桶(bucket)上的结点数大于这个值时会转成红黑树
            static final int TREEIFY_THRESHOLD = 8;
            // 当桶(bucket)上的结点数小于这个值时树转链表
            static final int UNTREEIFY_THRESHOLD = 6;
            // 桶中结构转化为红黑树对应的table的最小大小
            static final int MIN_TREEIFY_CAPACITY = 64;
            // 存储元素的数组,总是2的幂次倍
            transient Node<k,v>[] table;
            // 存放具体元素的集
            transient Set<map.entry<k,v>> entrySet;
            // 存放元素的个数,注意这个不等于数组的长度。
            transient int size;
            // 每次扩容和更改map结构的计数器
            transient int modCount;   
            // 临界值 当实际大小(容量*填充因子)超过临界值时,会进行扩容
            int threshold;
            // 填充因子
            final float loadFactor;
        }
        桶(bucket)代表数组中每一个节点存储的东西,他可能是链表或者是红黑树。
        
        
        HashMap对象的hash相同的话就会存在相同的桶里面,hash是通过key值算出来的。
        static final int hash(Object key) {
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        }
        
        DEFAULT_LOAD_FACTOR 填充因子 默认值为0.75 代表桶内存放数据的密度,如果该值越大,会存在某个桶的节点数过多,其他桶没有节点的情况。
        
        threshold 扩容阈值,当超过该值大小就会扩容。扩容以2的幂次数扩容。
        
        
        
        重要函数:
        
        put函数实际上调的是putVal函数
        
        public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }
        
        
        final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
            Node<K,V>[] tab; Node<K,V> p; int n, i;
            // 如果table为空初始化
            if ((tab = table) == null || (n = tab.length) == 0)
                n = (tab = resize()).length;
            // 计算新增的节点应该存放在table哪个位置,如果这个桶还是空的新建一个链表
            if ((p = tab[i = (n - 1) & hash]) == null)
                tab[i] = newNode(hash, key, value, null);
            // 桶中已经存在元素
            else {
                Node<K,V> e; K k;
                 // 比较桶中第一个元素(数组中的结点)的hash值相等,key相等
                if (p.hash == hash &&
                    ((k = p.key) == key || (key != null && key.equals(k))))
                    // 将第一个元素赋值给e,用e来记录
                    e = p;
                // hash值不相等,即key不相等 并且这个桶为红黑树
                else if (p instanceof TreeNode)
                 // 调用存放树节点的方法存放
                    e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                // 如果所在的桶是一个链表
                else {
                    // 在链表最末插入结点
                    for (int binCount = 0; ; ++binCount) {
                        // 到达链表的尾部
                        if ((e = p.next) == null) {
                            // 在尾部插入新结点
                            p.next = newNode(hash, key, value, null);
                            // 结点数量达到阈值,转化为红黑树
                            if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                treeifyBin(tab, hash);
                            // 跳出循环
                            break;
                        }
                        // 判断链表中结点的key值与插入的元素的key值是否相等
                        if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k))))
                            // 相等,跳出循环
                            break;
                        // 用于遍历桶中的链表,与前面的e = p.next组合,可以遍历链表
                        p = e;
                    }
                }
                // 表示在桶中找到key值、hash值与插入元素相等的结点
                if (e != null) {
                    // 记录e的value
                    V oldValue = e.value;
                    // onlyIfAbsent为false或者旧值为null
                    if (!onlyIfAbsent || oldValue == null)
                        //用新值替换旧值
                        e.value = value;
                    // 访问后回调
                    afterNodeAccess(e);
                    // 返回旧值
                    return oldValue;
                }
            }
            // 结构性修改
            ++modCount;
            // 实际大小大于阈值则扩容
            if (++size > threshold)
                resize();
            // 插入后回调
            afterNodeInsertion(evict);
            return null;
        }
        
        
        
        未完待续

        
        
        
        
        
        
        
        
       

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值