zoukankan      html  css  js  c++  java
  • HashMap

    java version "1.7.0_67"

    HashMap的草图:

    Entry数组:

    static final Entry<?,?>[] EMPTY_TABLE = {};
    transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
    transient int size; // map中键值对数量

    构造函数只是设置了 loadFactor 和 threshold 的值,所以table还是空的。

    装填因子loadFactor默认为0.75,loadFactor = 键值对数量 / 数组大小

    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
    
        this.loadFactor = loadFactor; //默认0.75
        threshold = initialCapacity; //默认16
        init();
    }
    
    void init() { }

    简单分析put操作:

    public V put(K key, V value) {
        //第一次put时,table是空的,需要扩容
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        //null也可以作为键
        if (key == null)
            return putForNullKey(value);
        //根据key的hashCode计算出hash值
        int hash = hash(key);
        //根据hash值,定位到table中的位置
        int i = indexFor(hash, table.length);
        //如果已存在相等key,更新value,并返回旧value
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            // 两个key相等的判断条件:
            //1. key的hash值相等,key的地址相等
            //2. key的hash值相等,key用equals比较相等
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
    
        modCount++;
        //不存在相等的key,则使用头插法加入链表中
        addEntry(hash, key, value, i);
        return null;
    }

    其实HashMap的内部数据结构还是比较清晰的,平常用得也挺多,听到最多的说法就是HashMap不是线程安全的,原因简单提一句,是在resize的过程中可能会产生环。

    分析下HashMap resize的过程:HashMap的数据迁移是一次性的,相对而言,redis的做法比较有趣,把数据迁移分摊到get和set操作上。当map中键值对数量超过threshold时,不一定会发生resize。

    void addEntry(int hash, K key, V value, int bucketIndex) {
        // 如果map中键值对的数量达到了threshold,且当前槽挂着entry
        if ((size >= threshold) && (null != table[bucketIndex])) {
            //2倍扩展
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            //扩展之后,table指向了新的数组,length也变了,重新计算index
            bucketIndex = indexFor(hash, table.length);
        }
    
        createEntry(hash, key, value, bucketIndex);
    }
    
    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);
                }
                int i = indexFor(e.hash, newCapacity);
                //这里也是使用头插法,所以原来链表的顺序会翻转
                e.next = newTable[i];
                newTable[i] = e;
                e = next;
            }
        }
    }
  • 相关阅读:
    【Educational Codeforces Round 101 (Rated for Div. 2) C】Building a Fence
    【Codeforces Round #698 (Div. 2) C】Nezzar and Symmetric Array
    【Codeforces Round #696 (Div. 2) D】Cleaning
    【Codeforces Round #696 (Div. 2) C】Array Destruction
    【Educational Codeforces Round 102 D】Program
    【Educational Codeforces Round 102 C】No More Inversions
    【Good Bye 2020 G】Song of the Sirens
    【Good Bye 2020 F】Euclid's nightmare
    使用mobx入门
    requestAnimationFrame 控制速度模拟setinterval
  • 原文地址:https://www.cnblogs.com/allenwas3/p/8442658.html
Copyright © 2011-2022 走看看