Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

HashMap data structures and features

We have been using HashMap for a long time and know that it is thread-unsafe. So why is it thread-unsafe? This article starts with the data structure and features of HashMap.

A hashMap principle

Using a HashMap is also easy, just put key-values in.

public static void main(String[] args) throws InterruptedException { HashMap map = new HashMap(); Map. Put (1, "zhang SAN "); Map. Put (2, "lI Si "); Map. Put (3, "king five "); Map. Put (4, "zhao 6 "); System.out.println("size:" + map.size()); }Copy the code

This is a common approach, and we don’t have to worry too much about the internal operations of a HashMap, just a simple call.

So what’s going on in the HashMap?

To open the HashMap class, we use new HashMap() as the entry point.

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // Constructs an empty HashMap with the default initial capacity (16) and the default load factor (0.75). // Constructs an empty HashMap with the default initial capacity (16) and the default load factor (0.75) Construct an empty hash map with a default initial capacity (16) and a default load factor (0.75). public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted }Copy the code

The load factor

There is a load factor, which sounds complicated, but it is a variable that represents the start of expansion when (capacity * load factor) is reached.

As for why the default load factor is 0.75, it’s probably a compromise. See an article on JDK1.7 that describes the load factor:

As a general rule, the default load factor (0.75) provides a good trade-off between time and space costs. Higher values reduce the space overhead but increase the cost of lookups (shown in most HashMap class operations, including GET and PUT). When setting the initial size, you should consider the expected number of entries in the map and its load factor, and minimize the number of rehash operations. If the initial capacity is greater than the maximum number of entries divided by the load factor, the rehash operation will not occur.Copy the code

The default volume

Looking at the source code, the default size of a HashMap is 1 << 4, which is 16.

When the threshold reaches (16 x 0.75), the capacity expansion starts

Expansion mechanism


static final int MAXIMUM_CAPACITY = 1 << 30;

Copy the code

The capacity of a HashMap is limited and must be less than 1<<30 (1073741824). If the capacity exceeds this number, it does not grow and the threshold is set to integer.max_value

Expansion mechanism in JDK1.7

Except that the constructor and default constructor specify some default values, if the capacity is not expanded for the first time, new capacity = old capacity * 2; New threshold = New capacity x load factor

Expansion mechanism in JDK1.8

Except that the constructor and default constructor specify some default values, if it is not the first expansion, the capacity is doubled and the threshold is doubled. (Load factor remains the same when capacity and threshold are doubled.)

The data structure


static class Node<K,V> implements Map.Entry<K,V> {

final int hash;

final K key;

V value;

Node<K,V> next;

}

Copy the code

Hash: Hash value of the key.

Key: the key to insert a value;

Value: the value;

Next: The next object.

From this code structure, you can see that HashMap uses a linked list data structure, also known as the zipper method.

Its most obvious feature is: the storage unit on the non-continuous, non-sequential storage structure, but in each node to the next node in the pointer field.

Is the put operation added to the top or bottom of the list

JDK 1.7 uses header insertion to add linked list elements. There is a problem with the looped list. In 1.8, we optimized the header insertion method to add linked list elements.