zoukankan      html  css  js  c++  java
  • 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;
                }
            }
        }
    想要体面生活,又觉得打拼辛苦;想要健康身体,又无法坚持运动。人最失败的,莫过于对自己不负责任,连答应自己的事都办不到,又何必抱怨这个世界都和你作对?人生的道理很简单,你想要什么,就去付出足够的努力。
  • 相关阅读:
    Leetcode Excel Sheet Column Number
    AlgorithmsI PA2: Randomized Queues and Deques Subset
    AlgorithmsI PA2: Randomized Queues and Deques RandomizedQueue
    AlgorithmsI PA2: Randomized Queues and Deques Deque
    AlgorithmsI Programming Assignment 1: PercolationStats.java
    hdu多校第四场 1003 (hdu6616) Divide the Stones 机智题
    hdu多校第四场 1007 (hdu6620) Just an Old Puzzle 逆序对
    hdu多校第四场1001 (hdu6614) AND Minimum Spanning Tree 签到
    hdu多校第三场 1007 (hdu6609) Find the answer 线段树
    hdu多校第三场 1006 (hdu6608) Fansblog Miller-Rabin素性检测
  • 原文地址:https://www.cnblogs.com/potentPrince/p/12557071.html
Copyright © 2011-2022 走看看