• hashMap 源码解析


    1、构造方法

     1 public HashMap() {
     2         this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
     3     }
     4 
     5  public HashMap(int initialCapacity) {
     6         this(initialCapacity, DEFAULT_LOAD_FACTOR);
     7     }
     8 
     9  public HashMap(int initialCapacity, float loadFactor) {
    10         if (initialCapacity < 0)
    11             throw new IllegalArgumentException("Illegal initial capacity: " +
    12                                                initialCapacity);
    13         if (initialCapacity > MAXIMUM_CAPACITY)
    14             initialCapacity = MAXIMUM_CAPACITY;
    15         if (loadFactor <= 0 || Float.isNaN(loadFactor))
    16             throw new IllegalArgumentException("Illegal load factor: " +
    17                                                loadFactor);
    18 
    19         this.loadFactor = loadFactor;
    20         threshold = initialCapacity;
    21         init();
    22     }
    23 
    24 public HashMap(Map<? extends K, ? extends V> m) {
    25         this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
    26                       DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
    27         inflateTable(threshold);
    28 
    29         putAllForCreate(m);
    30     }

    4种构造方法

    1、无参的构造方法,也就是我们最常用的构造方法,他给我们的默认的初始化 容量是16  也就是entry[]数组是16  ,entry 有什么参数? 

    一共4个参数,key, value ,hash ,还有一个就是Entry<K,V> next 对象中的对象,负载因子默认是0.75

    2、给一个数组大小的参数的是第二个构造函数

    3、给两个的是上面所说的两个参数的构造函数,内容就是检验入参,最后的是初始化链表,这里是个空的方法,为的是子类要可以重写方法

    put方法

    //入参是key和value 
    public V put(K key, V value) {
    判断表中是不是没有数据
            if (table == EMPTY_TABLE) {
    如果没有数据就调用这个方法(入参是容量* 负载因子)
                inflateTable(threshold);
            }
    如果key 为空返回下面的方法。作用:
            if (key == null)
                return putForNullKey(value);
            int hash = hash(key);
            int i = indexFor(hash, table.length);
            for (Entry<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;
        }
    
    
    /**
         * Inflates the table.
         */
        private void inflateTable(int toSize) {
            // 找到2的n次幂 >= 这个入参
    例如:2^4>15 这个capacity =16
            int capacity = roundUpToPowerOf2(toSize);
    获取合理的负载因子,
            threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
    新建一个这么大的容量的数组并复给table
            table = new Entry[capacity];
    //初始化哈希掩码值
            initHashSeedAsNeeded(capacity);
        }
    
    
    //入参是插入进来的value
      private V putForNullKey(V value) {
    循环这个数组的第一个数组 的链表,
            for (Entry<K,V> e = table[0]; e != null; e = e.next) {
    如果链表中的第一个值的 key值为空则把value值付给第一个原数的value
                if (e.key == null) {
                    V oldValue = e.value;
                    e.value = value;
    //空方法
                    e.recordAccess(this);
    //返回老的value值,就是对数组做操作仅仅是变更了一下value值,
                    return oldValue;
                }
            }
    数组变更次数加一
            modCount++;
    设置hash值为零,key值为null value为入参的值
            addEntry(0, null, value, 0);
            return null;
    
    
    void addEntry(int hash, K key, V value, int bucketIndex) {
    判断数组中的数据是否大于负载因子并且数组的第一个元素为空
            if ((size >= threshold) && (null != table[bucketIndex])) {
    扩2被的数值长度
                resize(2 * table.length);
    
                hash = (null != key) ? hash(key) : 0;
                bucketIndex = indexFor(hash, table.length);
            }
    
    入参是原来长度的2被
     void resize(int newCapacity) {
            Entry[] oldTable = table;
            int oldCapacity = oldTable.length;
    如果超过最大了就直接返回不扩容了
            if (oldCapacity == MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;
                return;
            }
    新建一个这么大的数组,
            Entry[] newTable = new Entry[newCapacity];
    把老的数组中的数转换到新数组中
            transfer(newTable, initHashSeedAsNeeded(newCapacity));
            table = newTable;
            threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
        }
    
    
       void transfer(Entry[] newTable, boolean rehash) {
            int newCapacity = newTable.length;
    循环原有的数组
            for (Entry<K,V> e : table) {
             循环每个链表
       while(null != e) {
                    Entry<K,V> next = e.next;
                    if (rehash) {
                        e.hash = null == e.key ? 0 : hash(e.key);
                    }重置这个hash值,与运算,也就是获取一个位置,放到先新的数组中的位置
                    int i = indexFor(e.hash, newCapacity);
                    e.next = newTable[i];
                    newTable[i] = e;
                    e = next;
                }
            }
        }
    想要体面生活,又觉得打拼辛苦;想要健康身体,又无法坚持运动。人最失败的,莫过于对自己不负责任,连答应自己的事都办不到,又何必抱怨这个世界都和你作对?人生的道理很简单,你想要什么,就去付出足够的努力。
  • 相关阅读:
    流体力学笔记 第二章 流体力学的基本概念
    jvm常用的参数
    链表的反转
    数据流中的中位数
    二叉树对称
    二叉树镜像
    输入框校验
    判断单选或者复选框中选中的值
    网页中window.open 弹出 父页面和子页面数值交互
    数组去重
  • 原文地址:https://www.cnblogs.com/potentPrince/p/12557071.html
Copyright © 2020-2023  润新知