说一说 HashMap 底层数据结构

作者: 宇宙之一粟 | 来源:发表于2020-08-22 22:34 被阅读0次

    答:HashMap 底层是数组 + 链表 + 红黑树的数据结构,数组的主要作用是方便快速查找,时间复杂度是 O(1),默认大小是 16,数组的下标索引是通过 key 的 hashcode 计算出来的,数组元素叫做 Node,当多个 key 的 hashcode 一致,但 key 值不同时,单个 Node 就会转化成链表,链表的查询复杂度是 O(n),当链表的长度大于等于 8 并且数组的大小超过 64 时,链表就会转化成红黑树,红黑树的查询复杂度是 O(log(n)),简单来说,最坏的查询次数相当于红黑树的最大深度。

    源码:

    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; // aka 16
        //最大容量
       static final int MAXIMUM_CAPACITY = 1 << 30;
    
       //负载因子默认值
       static final float DEFAULT_LOAD_FACTOR = 0.75f;
     
       //桶上的链表长度大于等于8时,链表转化成红黑树
       static final int TREEIFY_THRESHOLD = 8;
    
       //桶上的红黑树大小小于等于6时,红黑树转化成链表
       static final int UNTREEIFY_THRESHOLD = 6;
    
       //当数组容量大于 64 时,链表才会转化成红黑树
       static final int MIN_TREEIFY_CAPACITY = 64;
    
       //记录迭代过程中 HashMap 结构是否发生变化,如果有变化,迭代时会 fail-fast
       transient int modCount;
    
       //HashMap 的实际大小,可能不准(因为当你拿到这个值的时候,可能又发生了变化)
       transient int size;
    
       //存放数据的数组
       transient Node<K,V>[] table;
    
       // 扩容的门槛,有两种情况
       // 如果初始化时,给定数组大小的话,通过 tableSizeFor 方法计算,数组大小永远接近于 2 的幂次方,比如你给定初始化大小 19,实际上初始化大小为 32,为 2 的 5 次方。
       // 如果是通过 resize 方法进行扩容,大小 = 数组容量 * 0.75
       int threshold;
    
       //链表的节点
       static class Node<K,V> implements Map.Entry<K,V> {
     
       //红黑树的节点
       static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
    

    相关文章

      网友评论

        本文标题:说一说 HashMap 底层数据结构

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