HashMap源码解读

HashMap保存数据的结构是数组+单向链表,它集成AbstractMap类以及实现Map接口:

 

public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable
{
    //初始化大小16
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    //最大大小
    static final int MAXIMUM_CAPACITY = 1 << 30;
   //默认加载因子
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    static final Entry<?,?>[] EMPTY_TABLE = {};

    transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
    
     /**
     * The number of key-value mappings contained in this map.
     */
    transient int size;//map中key-value个数

    /**
     * The next size value at which to resize (capacity * load factor).
     * @serial
     */
    // If table == EMPTY_TABLE then this is the initial capacity at which the
    // table will be created when inflated.
    int threshold;//当size值大于等于threshold时需要扩容

 

 

HashMap有四个构造方法:

1、带初始化大小和加载因子的构造方法

public HashMap(int initialCapacity, float loadFactor)
public HashMap(Map<? extends K, ? extends V> m)

 2、带初始化大小的构造方法

public HashMap(int initialCapacity)

 3、无参构造方法

public HashMap() 

 4、带Map类型参数的构造方法

public HashMap(Map<? extends K, ? extends V> m)

 

在HashMap中,通过key的hash值来计算元素在数组table中的位置

int hash = hash(key);
int i = indexFor(hash, table.length);

如果hash相等key也相等的话,则替换原来的值:

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;
            }
        }

  

如果不同的key计算出来的位置相同,则这些key-value组成单向链表,当实际的数据个数大于等于临界值threshold时,则需要以原大小的2倍的对table进行扩容:

void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            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);
    }

 并且需要重新计算数据再新数组中的位置并复制到新数组中。

 

通过key取value时,也是先通过key的hash计算位置,再遍历链表:

public V get(Object key) {
        if (key == null)
            return getForNullKey();
        Entry<K,V> entry = getEntry(key);

        return null == entry ? null : entry.getValue();
    }

final Entry<K,V> getEntry(Object key) {
        if (size == 0) {
            return null;
        }

        int hash = (key == null) ? 0 : hash(key);
        //遍历链表
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        return null;
    }

 

猜你喜欢

转载自arthur2014.iteye.com/blog/2347104