Map collection of common Java class libraries

Posted by schilly on Mon, 31 Jan 2022 02:55:49 +0100

Map collection

  • Single value storage takes 1 value Collection
    • Duplicate sets are not allowed
    • Allow duplicate lists
  • Dual value storage Map: one key value pair data is stored each time

The map set stores key value pair data one by one. The key of the map set cannot be repeated. The key is mapped to the value object. Map cannot contain duplicate keys; Each key can map up to one value.

In the set set, there are HashSet and TreeSet, but they use HashMap and TreeMap respectively. In fact, they use double value stored Map to store single value. Set (HashSet, TreeSet, LinkedHashSet) uses Map set internally and only uses the location of key to store data, so that its own content can not be repeated.

Delete the data in the collection after use, otherwise it will occupy memory, so sometimes remove is used to fetch and delete the data

HashMap

The implementation of hash table adopts object array + linked list. When the length of linked list reaches a certain value, it will be converted into binary tree

Hash code, int, optimizes the performance of hash table. The hash values of the same attribute of the same class should be different

Hash table generation

  1. Everything is an object, and the corresponding hash value is generated according to the object (hashCode = 12313)
  2. The hash value is modeled according to the length of the array (hashCode%length = 12313%16)
  3. Store the object in the location corresponding to the index

Therefore, when querying the object, you can find its position in the hash table by remainder of the hash value without traversal.

For the same hash table, because the modular results of multiple hash values may be the same, a linked list (hash bucket) will be added at the position corresponding to the modular results. When the amount of data in the hash bucket is greater than 8, the linked list will be converted into a red black binary tree, which is more convenient for searching; However, when the amount of data in the hash bucket is reduced to 6, it will be converted from red black tree to linked list.

  • Number of initial barrels: 16
  • Hash factor: 0.75
  • When 75% of all hash buckets have been stored, the bucket will be expanded to twice the original length.
  • The initial capacity should be set reasonably to avoid repeated storage (constantly rebuilding the data structure)
  • The larger the hash factor is, the more space is saved and the query efficiency is low; The smaller the hash factor, the more space is wasted. The more efficient the query is.

HashMap/Hashtable/ConcurrentHashMap
TreeMap
LinkedHashMap
The use of is the same as the HashMap operation, indicating that the storage order is different due to the difference of data structure

HashMap part of the source code analysis

public V put(K key, V value) {
    //Hash value by key
    return putVal(hash(key), key, value, false, true);
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;

    //If it is an empty array, execute the resizing algorithm resize()
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;

    //The bit operation is equivalent to the hash value. Take the remainder of length to calculate the subscript. If there is no data, insert a new node
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        //Determine whether the key exists. The comparison hash value is the same and the key is exactly the same
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            //Insert linked list
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }

        //Key already exists
        if (e != null) { // existing mapping for key
            //Take out the old value first
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
            //assignment
                e.value = value;
            afterNodeAccess(e);
            //Return old value
            return oldValue;
        }
    }
    ++modCount;
    //If the threshold is exceeded, the capacity will be expanded
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

Traversal of HashMap

Use keySet() to return all keys, and get() to get their corresponding values

HashMap<String, String> data = new HashMap<>();

//Put key value pairs into the table
data.put("key1", "Hoe standing grain gradually pawning a midday");
data.put("key2", "Sweat drops under the grass");

//Get the value of key
String value1 = data.get("key1");
String value2 = data.get("key2");

//Get all the key values and put them in a collection Read the key value and return the value value through the forEach iteration
Set<String> set = data.keySet();
for (String s:set) {
    System.out.println(s);
    System.out.println(data.get(key));
}

Analysis of the differences among subclasses of map set

  • HashMap thread is unsafe and efficient
  • Hashtable is thread safe and inefficient
  • ConcurrentHashMap adopts segment lock mechanism to ensure thread safety and high efficiency
  • TreeMap uses binary tree to automatically sort and store, and HashMap does not guarantee the storage order
  • LinkedHashMap is in both hash table and bidirectional linked list

Problems needing attention when storing custom objects

Here, the book class is used as the key. The system calculates the hash value of book1 and stores it and the corresponding value in a bucket. At this time, if the content of book1 is changed, the content of the key in the table is also changed, but the position calculated by the original key does not change.

At this time, when searching with book1, the hash value will be returned first according to the new content. The result is that the get() method cannot find the location of its original hash value, so it cannot find the original value through this key.

At this time, if you create a new key book3 that is the same as the original key book3, although you can locate the location corresponding to the original book1 hash value, when you verify the contents of equals, it cannot match and the original value cannot be returned

Therefore, when an object is stored as an object for calculating the hash value (key), do not change it, otherwise the hash value will be disordered

HashMap<Book, String> data = new HashMap<>();
Book book1 = new Book("Golden Apple","xxxxxx");
data.put(book1,"First book");
Book book2 = new Book("princeling","xxxxxx");
data.put(book2,"Second book");
book1.setName("Silver Apple");
//When an object is stored as an object for calculating the hash value (key), do not change it, otherwise the hash value will be disordered
System.out.println(data.get(book1));
//null

Book book3 = new Book("Golden Apple","xxxxxx");
//null
//Although the hash value can find the object, but equals cannot be satisfied, the object is still not found

Topics: Java