Java集合学习-源码US现金盘平台出租实现细节-Set和Map

set与mapUS现金盘平台出租[ haozbbs.com ](http://haozbbs.com)Q1446595067 有非常大的关联。简单地说,把map的所有key拿出来就是一个set集合。map集合相当于一个存入了很多个key-value对象的set集合。相对应,set集合也可以如此扩展为map集合。
HashSet和HashMap都是利用Hash算法来决定(key的)存储位置,而map集合的value是紧跟着key存储的。
HashSet和HashMap对集合元素的存储方式

HashMap源码中的put方法

    //threshold:键值对数量的极限值
    //size:键值对的数量 

    /**
     * Associates the specified value with the specified key in this map.
     * If the map previously contained a mapping for the key, the old
     * value is replaced.
     * 将制定的值与此映射中的指定键关联。如果已经存在以前的映射,则替换旧值
     *
     * @param key   key with which the specified value is to be associated
     * @param value value to be associated with the specified key
     * @return the previous value associated with <tt>key</tt>, or
     * <tt>null</tt> if there was no mapping for <tt>key</tt>.
     * (A <tt>null</tt> return can also indicate that the map
     * previously associated <tt>null</tt> with <tt>key</tt>.)
     */
    public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        //根据key计算hash值
        int hash = hash(key);
        //找到在table中对应的索引
        int i = indexFor(hash, table.length);
        //如果该索引位置的Entry不是null,就遍历该索引位置的全部Entry
        for (HashMap.Entry<K, V> e = table[i]; e != null; e = e.next) {
            Object k;
            //hashCode相同则说明储存位置相同;
            // 再通过equals比较,如果相同,则覆盖原有value,并返回原有value。如果都不相同,则循环结束后执行addEntry方法
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        //如果索引i位置的Entry为null,调用addEntry方法
        addEntry(hash, key, value, i);
        return null;
    }

    //addEntry方法主要用来在需要的时候扩充table的大小,每次扩充一倍。然后调用了createEntry方法

    /**
     * Like addEntry except that this version is used when creating entries
     * as part of Map construction or "pseudo-construction" (cloning,
     * deserialization).  This version needn't worry about resizing the table.
     *
     * Subclass overrides this to alter the behavior of HashMap(Map),
     * clone, and readObject.
     */
    void createEntry(int hash, K key, V value, int bucketIndex) {
        //拿到制定索引处的Entry
        HashMap.Entry<K,V> e = table[bucketIndex];
        //在索引处放入新的Entry,并且新的Entry指向原来的Entry,没有则指向null
        table[bucketIndex] = new HashMap.Entry<>(hash, key, value, e);
        //map中键值对的数量
        size++;
    }

     /**
     * The table, resized as necessary. Length MUST Always be a power of two.
     */
    transient HashMap.Entry<K,V>[] table = (HashMap.Entry<K,V>[]) EMPTY_TABLE;

可以看到,table是一个数组,长度只能是2的n次方。在HashMap的一个构造方法中,系统会对构造时制定的容量大小做调整。所以创建HashMap时将初始容量设置为2的n次方,会减少系统计算开销。

猜你喜欢

转载自blog.51cto.com/13864470/2140358