zoukankan      html  css  js  c++  java
  • HashMap源码解析

    变量:

        /**
         * 初始化容量为16
         */
        static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    
        /**
         * 最大容量:2^30
         */
        static final int MAXIMUM_CAPACITY = 1 << 30;
    
        /**
         * 负载因子默认0.75,负载因子越小,hash冲突几率越低
         */
        static final float DEFAULT_LOAD_FACTOR = 0.75f;
    
        /**
         * 初始化一个空的数组
         */
        static final Entry<?,?>[] EMPTY_TABLE = {};
    
        /**
         * 存值的数组,初始化为空数组
         */
        transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
    
        /**
         * HashMap存入元素的个数
         */
        transient int size;
    
        /**
         * 临界值,HashMap能存储的大小,公式为(threshold=capacity*loadFactor)
         */
        // If table == EMPTY_TABLE then this is the initial capacity at which the
        // table will be created when inflated.
        int threshold;
    
        /**
         * 负载因子
         */
        final float loadFactor;
    
        /**
         *HashMap修改的次数,用于迭代
         */
        transient int modCount;
    
        /**
         * 最大值*/
        static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;

    构造方法:

        public HashMap(int initialCapacity, float loadFactor) {
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal initial capacity: " +
                                                   initialCapacity);
            if (initialCapacity > MAXIMUM_CAPACITY)//MAXIMUM_CAPACITY 最大容量
                initialCapacity = MAXIMUM_CAPACITY;
            if (loadFactor <= 0 || Float.isNaN(loadFactor))//loadFactor 负载因子
                throw new IllegalArgumentException("Illegal load factor: " +
                                                   loadFactor);
    
            this.loadFactor = loadFactor;
            threshold = initialCapacity;
            init();
        }

    走完构造方法,HashMap创建了一个空的数组,transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; 当使用put(K, V)存入键值对的时候,才会使用inflateTable(initialCapacity)初始化数组的大小为initialCapacity。下面是put(K, V)源码:

        public V put(K key, V value) {
            if (table == EMPTY_TABLE) {
                inflateTable(threshold);//初始化table的大小
            }
            if (key == null)
                return putForNullKey(value);
            int hash = hash(key);//根据key值计算出hash值
            int i = indexFor(hash, table.length);//根据hash值计算出数组的下标
            for (Entry<K,V> e = table[i]; e != null; e = e.next) {//如果当前数组上的链表头不为null,遍历链表
                Object k;
                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//不为null时,检测key值得hash是否相同,如果相同替换掉原来的值,并返回原来的值
                    V oldValue = e.value;
                    e.value = value;
                    e.recordAccess(this);
                    return oldValue;
                }
            }
    
            modCount++;//修改次数+1
            addEntry(hash, key, value, i);//添加元素
            return null;
        }
        private static int roundUpToPowerOf2(int number) {
            // assert number >= 0 : "number must be non-negative";
            return number >= MAXIMUM_CAPACITY
                    ? MAXIMUM_CAPACITY
                    : (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;//确保是2的倍数
        }
    
        /**
         * Inflates the table.
         */
        private void inflateTable(int toSize) {
            // Find a power of 2 >= toSize
            int capacity = roundUpToPowerOf2(toSize);
    
            threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);//临界值赋值
            table = new Entry[capacity];
            initHashSeedAsNeeded(capacity);
        }

    放入元素,如果是table是空数组,初始化table,临界值;

    key是null,将该entry放入到数组table的第0个下标处(第一个位置);

    根据key值计算出hash值,根据hash值计算出在数组table中的下标,根据下标找到链表,如果链表头不为null,遍历链表,检查key值是否存在于链表,如果存在,将新值替换掉旧值,并返回旧值;

    addEntry方法,将新的entry添加到链表头中。

        void addEntry(int hash, K key, V value, int bucketIndex) {
           Entry<K,V> e = table[bucketIndex];//记录原来的链表头
            table[bucketIndex] = new Entry<K,V>(hash, key, value, e);//表头引用该变成要插入的entry元素
            if (size++ >= threshold)
                resize(2 * table.length);//加入元素后,空间不足,扩容table长度的2倍
        }
  • 相关阅读:
    pip不是内部或外部命令也不是可运行的程序或批处理文件的问题
    动态规划 leetcode 343,279,91 & 639. Decode Ways,62,63,198
    动态规划 70.climbing Stairs ,120,64
    (双指针+链表) leetcode 19. Remove Nth Node from End of List,61. Rotate List,143. Reorder List,234. Palindrome Linked List
    建立链表的虚拟头结点 203 Remove Linked List Element,82,147,148,237
    链表 206 Reverse Linked List, 92,86, 328, 2, 445
    (数组,哈希表) 219.Contains Duplicate(2),217 Contain Duplicate, 220(3)
    重装系统
    java常用IO
    端口
  • 原文地址:https://www.cnblogs.com/teiba/p/9087669.html
Copyright © 2011-2022 走看看