HashMap and hashmap usage

Source: Internet
Author: User
Tags concurrentmodificationexception

HashMap and hashmap usage
HashMap

HashMap is a non-synchronous implementation based on the Map interface of the hash table. The null value and the null key are allowed.

Data Structure

/*** The table, resized as necessary. length MUST Always be a power of two. */transient Entry [] table; static class Entry <K, V> implements Map. entry <K, V> {final K key; V value; Entry <K, V> next; final int hash ;...... }

An Entry is an element in an array. Each Map. Entry is actually a key-value pair. It holds a reference pointing to the next element, which constitutes a linked list.

Access Implementation
Public V put (K key, V value) {// HashMap allows null keys and null values to be stored. // When the key is null, call the putForNullKey method to place the value in the first position of the array. If (key = null) return putForNullKey (value); // recalculate the hash value based on the key's keyCode. Int hash = hash (key. hashCode (); // search for the index of the specified hash value in the corresponding table. Int I = indexFor (hash, table. length); // If the Entry at the I index is not null, The next element of e is continuously traversed through loops. 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 ;}// if the Entry at the I index is null, no Entry exists. ModCount ++; // Add the key and value to the I index. AddEntry (hash, key, value, I); return null ;}

When we put an element in a HashMap, we first re-calculate the hash value based on the hashCode of the key, and calculate the position (subscript) of the element in the Array Based on the hash value ), if the array already contains other elements in this position, the elements in this position will be stored in the form of a linked list, the newly added elements will be placed in the chain header, and the first elements will be placed at the end of the chain. If no element exists in the position of the array, the element is directly placed in this position of the array.

The addEntry (hash, key, value, I) method places the key-value pair in the I index of the array table based on the calculated hash value. AddEntry is a package access permission method provided by HashMap. The Code is as follows:

Void addEntry (int hash, K key, V value, int bucketIndex) {// obtain the Entry at the specified bucketIndex <K, V> e = table [bucketIndex]; // place the newly created Entry to the bucketIndex index and point the new Entry to the original Entry table [bucketIndex] = new Entry <K, V> (hash, key, value, e); // if the number of key-value pairs in the Map exceeds the limit if (size ++> = threshold) // The length of the table object is doubled. Resize (2 * table. length );}

The hash (int h) method recalculates a hash Based on the hashCode of the key. This algorithm is added to high-level computing to prevent hash conflicts when the low-level remains unchanged and the high-level changes.

static int hash(int h) {      h ^= (h >>> 20) ^ (h >>> 12);      return h ^ (h >>> 7) ^ (h >>> 4);  }

For any given object, as long as its hashCode () returns the same value, the hash code value calculated by the Program Calling the hash (int h) method is always the same. The first thing we think of is the modulo operation of the hash value on the array length. In this way, the element distribution is relatively even. However, the consumption of the "modulo" operation is still relatively large. In HashMap, this is done by calling indexFor (int h, int length) to calculate the index of the table array. The code for indexFor (int h, int length) is as follows:

static int indexFor(int h, int length) {      return h & (length-1);  }

It obtains the storage space of this object through h & (table. length-1), while the length of the underlying array of HashMap is always 2 to the nth power, which is the Speed Optimization of HashMap.

int capacity = 1;      while (capacity < initialCapacity)          capacity <<= 1;

This Code ensures that the capacity of HashMap during initialization is always the Npower of 2, that is, the length of the underlying array is always the Npower of 2.

When length is always the N power of 2, the h & (length-1) operation is equivalent to the modulo of length, that is, h % length, but & is more efficient than %.

 

public V get(Object key) {      if (key == null)          return getForNullKey();      int hash = hash(key.hashCode());      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.equals(k)))              return e.value;      }      return null;  }

When getting an element from a HashMap, first calculate the hashCode of the key, find an element in the corresponding position in the array, and then find the desired element in the linked list at the corresponding position through the key equals method.

 

In summary, HashMap treats key-value as a whole at the underlying layer, which is an Entry object. At the underlying layer of HashMap, an Entry [] array is used to store all key-value pairs. When an Entry object needs to be stored, its storage location in the array is determined based on the hash algorithm, the storage location of the linked list on the array location is determined based on the equals method. When an Entry needs to be retrieved, the storage location in the array is also found based on the hash algorithm, then, the Entry is retrieved from the linked list at the position according to the equals method.

Fail-Fast Mechanism

We know that java. util. HashMap is NOT thread-safe. Therefore, if other threads modify map during the use of the iterator, ConcurrentModificationException will be thrown, which is the so-called fail-fast policy.

The implementation of this policy in the source code is implemented through the modCount field. As the name suggests, modCount is the number of modifications, and the modification to the HashMap content will increase this value, this value will be assigned to the expectedModCount of the iterator during the iterator initialization process.

HashIterator() {      expectedModCount = modCount;      if (size > 0) { // advance to first entry      Entry[] t = table;      while (index < t.length && (next = t[index++]) == null)          ;      }  }

During iteration, determine whether modCount and expectedModCount are equal. If they are not equal, other threads have modified Map:

Note that modCount is declared as volatile to ensure the visibility of modifications between threads.

final Entry<K,V> nextEntry() {         if (modCount != expectedModCount)             throw new ConcurrentModificationException();

The fast failure behavior of the iterator cannot be guaranteed. In general, it is impossible to make any firm guarantee when there are non-synchronous concurrent modifications. The quick failure iterator tries its best to throw ConcurrentModificationException. Therefore, writing a program dependent on this exception is incorrect. The correct practice is: the fast failure behavior of the iterator should be

It is only used to detect program errors.

I am the dividing line of tiantiao
Hashmap Traversal

Method 1
Iterator iterator = hm. keySet (). iterator ();
While (iterator. hasNext ()){
System. out. println (hm. get (iterator. next ()));
}
Method 2
Set set = hm. entrySet ();
Java. util. Iterator it = hm. entrySet (). iterator ();
While (it. hasNext ()){
Java. util. Map. Entry entry = (java. util. Map. Entry) it. next ();
// Entry. getKey () returns the key corresponding to this item.
// Entry. getValue () returns the value corresponding to this item.
System. out. println (entry. getValue ());
}

Recommended method 1

Hashmap Traversal

Method 1
Iterator iterator = hm. keySet (). iterator ();
While (iterator. hasNext ()){
System. out. println (hm. get (iterator. next ()));
}
Method 2
Set set = hm. entrySet ();
Java. util. Iterator it = hm. entrySet (). iterator ();
While (it. hasNext ()){
Java. util. Map. Entry entry = (java. util. Map. Entry) it. next ();
// Entry. getKey () returns the key corresponding to this item.
// Entry. getValue () returns the value corresponding to this item.
System. out. println (entry. getValue ());
}

Recommended method 1

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.