Hashtable (jdk1.8) source code analysis

Definition of hashtable:

public class HashTable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable
Inherited from Dictionary, Dictionary is an abstract parent class with the same functions as Map, but it is outdated. It is officially recommended to implement the Map interface instead. 
And implements the Map interface, as well as the Cloneable, Serializable interface.


The difference with hashMap:

null value problem

HashTable key (key) and value (value) cannot be null. 


/**
     * Add the key and value to the map, clearly marked,
     *value cannot be null. If the key is null, a nullPointer exception will be reported */
    public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }
        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        //It is very straightforward to use hashcode to remove table.length, and then take the length.
        int index = (hash & 0x7FFFFFFF) % tab.length;

        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        //There is data behind the linked list
        for(; entry != null ; entry = entry.next) {
            if ((entry.hash == hash) && entry.key.equals(key)) {
                //Hash is the same and equals, then it is connected in the back, in the form of a linked list.
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }
        //First, there is no data behind the linked list.
        addEntry(hash, key, value, index);
        return null;
    }
Regarding value, there is obviously an if judgment, which cannot be null. 

If the key is null, a null pointer will be reported directly when the hashCode is calculated.


Calculate table array index value method

        int hash = key.hashCode (); // direct hashcode% n
        int index = (hash & 0x7FFFFFFF) % tab.length;

而hashmap    int index=e.hash  % n ; 

 The hash value is calculated differently! It is very straightforward to use hashcode to remove table.length, and then take the length.


HashTable is thread safe

Because most of the methods in HashTable are added with the synchronized keyword, only one thread can enter its method at the same time, so it is thread-safe.


initialCapacity和loadFactor

HashMap中:initialCapacity=16,loadFactory=0.75HashTable中:initialCapacity=11,loadFactory=0.75 


Only the linked list method resolves conflicts

In Java8, HashMap, when there is a conflict,

  • If the number of conflicts is less than 8, the conflicts are resolved in a linked list manner.
  • When the conflict is greater than or equal to 8, the conflicting Entry will be converted into a red-black tree for storage.
  • And when the number is less than 6, it is converted into linked list storage.

In HashTable,   it is stored in a linked list.


Amount of expansion

In Java8, HashMap: 
Once expanded, it is expanded to a multiple of 2, because it is beneficial to calculate the array index value, that is, it is combined with the calculation of the array index.

HashTable: One-time expansion to oldCapacity*2+1. 


/**
     * One expansion is, old*2+1
     */
    @SuppressWarnings("unchecked")
    protected void rehash() {
        int oldCapacity = table.length;
        Entry<?,?>[] oldMap = table;

        // overflow-conscious code
        int newCapacity = (oldCapacity << 1) + 1;
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            if (oldCapacity == MAX_ARRAY_SIZE)
                // Keep running with MAX_ARRAY_SIZE buckets
                return;
            newCapacity = MAX_ARRAY_SIZE;
        }
        Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];

        modCount++;
        //The new threshold value. Take the small value of newCapacity*loadFactor.
        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        table = newMap;

        for (int i = oldCapacity ; i-- > 0 ;) {
            for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
                Entry<K,V> e = old;
                old = old.next;
                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                e.next = (Entry<K,V>)newMap[index];
                newMap[index] = e;
            }
        }
    }
Expand first, and then add the elements in the old array to the new one one by one. 

Note that the  hash taken here is not e.hash, but is still the value retained by the key.hashCode calculation. 


refer to:

https://blog.csdn.net/anla_/article/details/78298484

https://blog.csdn.net/zldeng19840111/article/details/6703104

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325816490&siteId=291194637