HashMap depth understanding of the mechanism of expansion

Original link: https://www.cnblogs.com/yanzige/p/8392142.html

First, when the expansion:

Online summary there will be many, but most are summarized incomplete or inaccurate. Most likely to say the value of the following conditions are satisfied me one.

Expansion must meet two conditions:

1, when storing a new value of the current number of elements must have a threshold value greater than or equal

2, when storing new data value currently stored hash collision occurs (position of the current array index key hash value calculated out in terms of value already exists)

 

Second, let's look at the source code, as follows:

The first is the put () method

public V put(K key, V value) {

    //判断当前Hashmap(底层是Entry数组)是否存值(是否为空数组)

    if (table == EMPTY_TABLE) {

      inflateTable(threshold);//如果为空,则初始化

    }

    

    //判断key是否为空

    if (key == null)

      return putForNullKey(value);//hashmap允许key为空

    

    //计算当前key的哈希值    

    int hash = hash(key);

    //通过哈希值和当前数据长度,算出当前key值对应在数组中的存放位置

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

    for (Entry<K,V> e = table[i]; e != null; e = e.next) {

      Object k;

      //如果计算的哈希位置有值(及hash冲突),且key值一样,则覆盖原值value,并返回原值value

      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;

  }

   

There the addEntry call () method put () method, which is specific to this approach stored values, whether or not there is determined before the stored-value capacity is needed

void addEntry(int hash, K key, V value, int bucketIndex) {

    //1、判断当前个数是否大于等于阈值

    //2、当前存放是否发生哈希碰撞

    //如果上面两个条件否发生,那么就扩容

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

  }

  

If capacity is needed, call the expansion method resize ()

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()方法把原数组中的值放到新数组中

    transfer(newTable, initHashSeedAsNeeded(newCapacity));

    //设置hashmap扩容后为新的数组引用

    table = newTable;

    //设置hashmap扩容新的阈值

    threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);

  }

 

transfer () in the actual expansion when the original elements of the array into a new array

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

        }

        //通过key值的hash值和新数组的大小算出在当前数组中的存放位置

        int i = indexFor(e.hash, newCapacity);

        e.next = newTable[i];

        newTable[i] = e;

        e = next;

      }

    }

  }

  

Third, the summary:

Hashmap expansion required to meet two conditions: the current amount of data stored (i.e., size ()) must be greater than equal to a threshold size; whether the current data is added to the hash conflict occurs.

 

Since the above two conditions, the presence of such things as

(1), the value is stored in the hashmap of time (the default size is 16, the load factor of 0.75, the threshold 12), may reach the last 16 values ​​is full time, and then stored in the first 17 values ​​of the expansion phenomenon will occur, because the first 16 values ​​each occupy a position in the bottom of the array, hash collision does not occur.

(2), of course, also possible to store more value (more than 16 super value, you can save up to 26 value) have not expansion. Principle: Before a collision hash values ​​of all 11, to keep the same position of the array (in this case the number of elements less than the threshold value 12, not expansion), all 15 values ​​back into the dispersion to all remaining array positions 15 (in this case the number of elements not less than the threshold value, but each element is not stored in hash collision occurs, it will not expansion), the first 11 + 15 = 26, so it satisfies the above values ​​into the 27th time two conditions, when will this expansion phenomenon.

 

Note: jdk version 1.7

Guess you like

Origin blog.csdn.net/ysl19910806/article/details/100139717