HashTable

Hashtable


1. Contrast HashMap

1.
project HashMap Hashtable
Default capacity 16 11
load factor 0.75 0.75
null value Allow key/value to be empty Do not allow key/value to be empty (null pointer exception during put operation)
Expansion length*2 length*2+1
Safety thread unsafe thread safety
extends AbstractMap Dictionary
capacity >=1 2^n


2. The load factor is
too low , the space utilization is low, the frequent expansion is
too high, the addressing time increases, and the key value is too much;

3. The fast failure
modCount

is in the traversal process, if modCount > expectedCount
throw new ConcurrentModificationException

2. Class definition

1. Source code
public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable


3. Properties

1. Source code
    /**
     * The hash table data.
     */
    // array of Entry, Entry
    private transient Entry[] table;

    /**
     * The total number of entries in the hash table.
     */
    // capacity
    private transient int count;

    /**
     * The table is rehashed when its size exceeds this threshold.  (The
     * value of this field is (int)(capacity * loadFactor).)
     *
     * @serial
     */
    // critical value
    private int threshold;

    /**
     * The load factor for the hashtable.
     *
     * @serial
     */
    // load factor
    private float loadFactor;

    /**
     * The number of times this Hashtable has been structurally modified
     * Structural modifications are those that change the number of entries in
     * the Hashtable or otherwise modify its internal structure (e.g.,
     * rehash).  This field is used to make iterators on Collection-views of
     * the Hashtable fail-fast.  (See ConcurrentModificationException).
     */
    // modification times
    private transient int modCount = 0;

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = 1421746759512286392L;



Fourth, the construction method

1.
    // Initialize capacity, load factor
    public Hashtable(int initialCapacity, float loadFactor) {
        // Initialize capacity cannot be less than 0
	if (initialCapacity < 0)
	    throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        // The load factor cannot be less than 0 and it is a float type of data
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal Load: "+loadFactor);

        if (initialCapacity==0)
        // Initialize the capacity to any number, HashMap must be the N power of 2
            initialCapacity = 1;
	this.loadFactor = loadFactor;
	table = new Entry[initialCapacity];
	threshold = (int)(initialCapacity * loadFactor);
    }


2.
    // default load factor 0.75
    public Hashtable(int initialCapacity) {
	this(initialCapacity, 0.75f);
    }

    /**
     * Constructs a new, empty hashtable with a default initial capacity (11)
     * and load factor (0.75).
     */
    // default initialize capacity 11
    public Hashtable() {
	this(11, 0.75f);
    }



3. Take an existing collection as a parameter

    /**
     * Constructs a new hashtable with the same mappings as the given
     * Map.  The hashtable is created with an initial capacity sufficient to
     * hold the mappings in the given Map and a default load factor (0.75).
     *
     * @param t the map whose mappings are to be placed in this map.
     * @throws NullPointerException if the specified map is null.
     * @since   1.2
     */
    public Hashtable(Map<? extends K, ? extends V> t) {
        // Call the constructor, and the initialization capacity is twice the number of key-value pairs in the existing set
	this(Math.max(2*t.size(), 11), 0.75f);
	putAll(t);
    }

    // Traverse the existing collection, call the put method, synchronized keyword, thread safety
    public synchronized void putAll(Map<? extends K, ? extends V> t) {
        for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
            put(e.getKey(), e.getValue());
    }



Five, put ()

1. Source code
    
    public synchronized V put(K key, V value) {
	// Make sure the value is not null

        // value is not allowed to be null, null pointer exception
	if (value == null) {
	    throw new NullPointerException();
	}

	// Makes sure the key is not already in the hashtable.
        // assign
	Entry tab[] = table;

        // key cannot be empty, otherwise a null pointer exception will be reported when the hashcode is obtained
        // A hash, the hash value of the key itself
	int hash = key.hashCode();
        // Calculate the hash value twice, and then take the remainder with the length to determine the position stored in the array
	int index = (hash & 0x7FFFFFFF) % tab.length;
        // Take out the data at the index position, traverse the linked list under the array, and determine whether the key already exists
        // If it already exists, replace the existing value and return the old value
	for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
	    if ((e.hash == hash) && e.key.equals(key)) {
		V old = e.value;
		e.value = value;
		return old;
	    }
	}
        // increment the number of operations by 1
	modCount++;
        // Whether the number count of Entry in Hashtable is greater than the critical value
	if (count >= threshold) {
	    // Rehash the table if the threshold is exceeded
            // expand
	    rehash();

            tab = table;
            index = (hash & 0x7FFFFFFF) % tab.length;
	}

	// Creates the new entry.
        // Assign the linked list at tab[index] position to e
	Entry<K,V> e = tab[index];
        // Add an Entry and put the original linked list in the next of the newly added Entry
        // That is, the newly added Entry is placed at the top of the linked list
	tab[index] = new Entry<K,V>(hash, key, value, e);
	count++;
	return null;
    }

    // Constructor of Entry
	protected Entry(int hash, K key, V value, Entry<K,V> next) {
	    this.hash = hash;
	    this.key = key;
	    this.value = value;
	    this.next = next;
	}
     
    // expand
    protected void rehash() {
        // Capacity before expansion
	int oldCapacity = table.length;
	Entry[] oldMap = table;
        // The expanded capacity length*2 + 1
	int newCapacity = oldCapacity * 2 + 1;
	Entry[] newMap = new Entry[newCapacity];
        // increment the number of operations by 1
	modCount++;
	threshold = (int)(newCapacity * loadFactor);
	table = newMap;

        // Two-layer loop, the outer layer traverses the total length of the original array, and puts the old array into the new array in turn
	for (int i = oldCapacity ; i-- > 0 ;) {
            // Get the linked list at index i in the old data
	    for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
                // Get the element value at the current position of the linked list
		Entry<K,V> e = old;
                // pointer down
		old = old.next;
                // Calculate storage location
		int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                // The current element points to the index subscript position in the new array
		e.next = newMap[index];
                // The index position of the new array points to e
		newMap[index] = e;
	    }
            // The result of the traversal is to put the elements in the linked list upside down into a new array
	}
    }
    


Six, remove ()
1. Source code
    public synchronized V remove(Object key) {
	Entry tab[] = table;
	int hash = key.hashCode();
        // locate the storage location
	int index = (hash & 0x7FFFFFFF) % tab.length;
	for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
	    if ((e.hash == hash) && e.key.equals(key)) {
		modCount++;
              // If the number of elements in the linked list is > 1, point the previous Entry.next to the next of the current element
		if (prev != null) {
		    prev.next = e.next;
		} else {
                    // traverse the conditions
                    // Entry<K,V> e = tab[index], prev = null
                    // In the next loop, assign prev = e; if prev == null
                    // Explain that the first Entry in the linked list is the target
		    tab[index] = e.next;
		}
		count--; // count represents the number of stored Entry
		V oldValue = e.value;
		e.value = null;
		return oldValue;
	    }
	}


Seven, get ()

1. Source code

    public synchronized V get(Object key) {
	Entry tab[] = table;
        // key cannot be null, a null pointer is reported here
	int hash = key.hashCode();
	int index = (hash & 0x7FFFFFFF) % tab.length;
	for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
	    if ((e.hash == hash) && e.key.equals(key)) {
		return e.value;
	    }
	}
	return null;
    }

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326858447&siteId=291194637