Hashtable implementation principle

Source: Internet
Author: User
Tags rehash

Reprinted: http://wiki.jikexueyuan.com/project/java-collection/hashtable.html

Overview

Like hashmap, hashtable is also a hash that stores key-value pairs.

Hashtable is defined in Java:

public class Hashtable<K,V>      extends Dictionary<K,V>      implements Map<K,V>, Cloneable, java.io.Serializable{}

From the source code, we can see that hashtable inherits from the dictionary class and implements the map, cloneable, and Java. Io. serializable interfaces. The dictionary class is an abstract parent class of any class (such as hashtable) that maps keys to corresponding values. Each key and value is an object (source code comment:DictionaryClass is the abstract parent of any class, suchHashtable, Which maps keys to values. Every key and every value is an object .). But at this point I began to have some doubts, because I checked the source code of hashmap and treemap, and they did not inherit from this class. However, when I see the explanations in the annotations, the dictionary source code annotation is as follows: Note: This class is obsolete. new implementations shocould implement the map interface, rather than extending this class. this indicates that the dictionary class is out of date. The new implementation class should implement the map interface.

Interpreting member variables with hashtable source code

Hashtable is a hash table implemented by the "Zipper method. It includes several important member variables: Table, Count, threshold, loadfactor, and modcount.

  • Table is an entry [] array type, and entry (explained in hashmap) is actually a one-way linked list. The "key-value pairs" of the hash table are all stored in the entry array.
  • Count is the size of hashtable, which is the number of key-value pairs saved by hashtable.
  • Threshold is the hashtable threshold, used to determine whether to adjust the hashtable capacity. Value of Threshold = "capacity * loading factor ".
  • Loadfactor is the load factor.
  • Modcount is used to implement the fail-fast mechanism.

The interpretation of variables is included in the source code comments. It is best to read the English comments.

/**     * The hash table data.     */    private transient Entry<K,V>[] table;    /**     * The total number of entries in the hash table.     */    private transient int count;    /**     * The table is rehashed when its size exceeds this threshold.  (The     * value of this field is (int)(capacity * loadFactor).)     *     * @serial     */    private int threshold;    /**     * The load factor for the hashtable.     *     * @serial     */    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).     */    private transient int modCount = 0;
Constructor

Hashtable provides four constructor methods:

  • public Hashtable(int initialCapacity, float loadFactor): Create a New empty hash table with the specified initial capacity and the specified loading factor. Usealthashing is boolean. If it is true, another hash string key is executed to reduce hash conflicts caused by weak hash calculation.
  • public Hashtable(int initialCapacity): Create a New empty hash table with the specified initial capacity and the default load factor (0.75.
  • public Hashtable(): Default constructor. The capacity is 11 and the load factor is 0.75.
  • public Hashtable(Map<? extends K, ? extends V> t): Construct a new hash table with the same ing relationship with the given map.
/**     * Constructs a new, empty hashtable with the specified initial     * capacity and the specified load factor.     *     * @param      initialCapacity   the initial capacity of the hashtable.     * @param      loadFactor        the load factor of the hashtable.     * @exception  IllegalArgumentException  if the initial capacity is less     *             than zero, or if the load factor is nonpositive.     */    public Hashtable(int initialCapacity, float loadFactor) {        if (initialCapacity < 0)            throw new IllegalArgumentException("Illegal Capacity: "+                                               initialCapacity);        if (loadFactor <= 0 || Float.isNaN(loadFactor))            throw new IllegalArgumentException("Illegal Load: "+loadFactor);        if (initialCapacity==0)            initialCapacity = 1;        this.loadFactor = loadFactor;        table = new Entry[initialCapacity];        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);        useAltHashing = sun.misc.VM.isBooted() &&                (initialCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);    }    /**     * Constructs a new, empty hashtable with the specified initial capacity     * and default load factor (0.75).     *     * @param     initialCapacity   the initial capacity of the hashtable.     * @exception IllegalArgumentException if the initial capacity is less     *              than zero.     */    public Hashtable(int initialCapacity) {        this(initialCapacity, 0.75f);    }    /**     * Constructs a new, empty hashtable with a default initial capacity (11)     * and load factor (0.75).     */    public Hashtable() {        this(11, 0.75f);    }    /**     * 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) {        this(Math.max(2*t.size(), 11), 0.75f);        putAll(t);    }
Put Method

The entire process of the put method is:

  1. Determines whether the value is null. If it is null, an exception is thrown;
  2. Calculate the hash value of the key and obtain the position index of the key in the Table Array Based on the hash value. If the table [Index] element is not empty, it is iterated. If the same key is encountered, directly replace and return the old value;
  3. Otherwise, we can insert it to the table [Index] position.

I have made some comments in the following code:

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. // ensure that the key is not in hashtable. // first, calculate the hash value of the key using the hash method, calculate the index value, and determine its position in table []. // second, iterate the linked list at the index position. If the linked list at the position has the same key, replace the value and return the old value entry tab [] = table; int hash = hash (key); int Index = (hash & 0x7fff FFFF) % tab. length; 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 ;}} modcount ++; If (count> = threshold) {// rehash the table if the threshold is exceeded // if the threshold value is exceeded, rehash (); tab = table; hash = hash (key); Index = (hash & 0x7fffff) % tab. length;} // creates the new entry. // Insert the value and return NULL entry <K, V> E = tab [Index]; // create a new entry node, insert the new entry into the index position of hashtable, and set E to the next element of the new entry, Tab [Index] = new entry <> (hash, key, value, e ); count ++; return NULL ;}

An example is provided to illustrate the process:

Assume that the hashtable capacity is 5 and there are five key-value pairs (5, 5), (13, 13), (16, 16), (17, 17), and, their position in hashtable is as follows:

Now, we insert a new key-value pair, put (16, 22). Assume that the index of key = 16 is 1. but now there are two entries at Index 1, so the program will iterate on the linked list. During iteration, we find that the key of an entry is the same as the key of the key-value pair we want to insert. So now we will replace newvalue = 22 with oldvalue = 16, then return oldvalue = 16.

Then we insert another put (), Key = 33 index is 3, and there is no entry with key = 33 in the linked list, therefore, insert the node into the first position of the linked list.

Get Method

Compared with the put method, the get method is much simpler. The process is to first obtain the hash value of the key through the hash () method, and then index the key based on the hash value (the algorithms used in the preceding two steps are the same as those used in the put method ). Then, the linked list is iterated to return the corresponding value of the matched key. If no value is found, null is returned.

public synchronized V get(Object key) {        Entry tab[] = table;        int hash = hash(key);        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;    }
Hashtable Traversal

Hashtable has multiple traversal methods:

// 1. Use keys () Enumeration <string> EN1 = table. keys (); While (en1.hasmoreelements () {en1.nextelement ();} // 2. Use elements () Enumeration <string> EN2 = table. elements (); While (en2.hasmoreelements () {en2.nextelement ();} // 3. Use keyset () iterator <string> it1 = table. keyset (). iterator (); While (it1.hasnext () {it1.next ();} // 4. Use entryset () iterator <entry <string, string> it2 = table. entryset (). iterator (); While (it2.hasnext () {it2.next ();}
Simple comparison between hashtable and hashmap
  1. Hashtable is based on the dictionary class, while hashmap is based on abstractmap. Dictionary is an abstract parent class of any class that maps keys to corresponding values. abstractmap is implemented based on the map interface to minimize the work required to implement this interface.
  2. The key and value of hashmap can both be null, while the key and value of hashtable cannot be null. When hashmap encounters a null key, it calls the putfornullkey method for processing, but does not process the value. If hashtable encounters null, it returns nullpointerexception directly.
  3. The hashtable method is synchronous, while the hashmap method is not. Let's take a look at the source code. Almost all public methods in hashtable are synchronized, and some methods are implemented internally through the synchronized code block. Therefore, it is generally recommended that hashmap be used if multi-thread synchronization is involved, but there is a static method in the collections class: synchronizedmap (), this method creates a thread-safe map object and returns it as an encapsulated object.

Hashtable implementation principle

Related Article

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.