java集合-HashTable,java-hashtable

來源:互聯網
上載者:User

java集合-HashTable,java-hashtable
概述

和 HashMap 一樣,Hashtable 也是一個散列表,它儲存的內容是索引值對。

Hashtable 在 Java 中的定義為:

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

 從源碼中,我們可以看出,Hashtable 繼承於 Dictionary 類,實現了 Map, Cloneable, java.io.Serializable介面。其中Dictionary類是任何可將鍵映射到相應值的類(如 Hashtable)的抽象父類,每個鍵和值都是對象.

成員變數

Hashtable是通過"拉鏈法"實現的雜湊表。它包括幾個重要的成員變數:table, count, threshold, loadFactor, modCount。

  • table是一個 Entry[] 數群組類型,而 Entry(在 HashMap 中有講解過)實際上就是一個單向鏈表。雜湊表的"key-value索引值對"都是儲存在Entry數組中的。
  • count 是 Hashtable 的大小,它是 Hashtable 儲存的索引值對的數量。
  • threshold 是 Hashtable 的閾值,用於判斷是否需要調整 Hashtable 的容量。threshold 的值="容量*載入因子"。
  • loadFactor 就是載入因子。

modCount 是用來實現 fail-fast 機制的。

/**     * 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;
構造方法

Hashtable 一共提供了 4 個構造方法:

    • public Hashtable(int initialCapacity, float loadFactor): 用指定初始容量和指定載入因子構造一個新的空雜湊表。useAltHashing 為 boolean,其如果為真,則執行另一散列的字串鍵,以減少由於弱雜湊計算導致的雜湊衝突的發生。
    • public Hashtable(int initialCapacity):用指定初始容量和預設的載入因子 (0.75) 構造一個新的空雜湊表。
    • public Hashtable():預設建構函式,容量為 11,載入因子為 0.75。
    • public Hashtable(Map<? extends K, ? extends V> t):構造一個與給定的 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 方法

put 方法的整個流程為:

下面的代碼中也進行了一些注釋:

public synchronized V put(K key, V value) {        // Make sure the value is not null確保value不為null        if (value == null) {            throw new NullPointerException();        }        // Makes sure the key is not already in the hashtable.        //確保key不在hashtable中        //首先,通過hash方法計算key的雜湊值,並計算得出index值,確定其在table[]中的位置        //其次,迭代index索引位置的鏈表,如果該位置處的鏈表存在相同的key,則替換value,返回舊的value        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)) {                V old = e.value;                e.value = value;                return old;            }        }        modCount++;        if (count >= threshold) {            // Rehash the table if the threshold is exceeded            //如果超過閥值,就進行rehash操作            rehash();            tab = table;            hash = hash(key);            index = (hash & 0x7FFFFFFF) % tab.length;        }        // Creates the new entry.        //將值插入,返回的為null        Entry<K,V> e = tab[index];        // 建立新的Entry節點,並將新的Entry插入Hashtable的index位置,並設定e為新的Entry的下一個元素        tab[index] = new Entry<>(hash, key, value, e);        count++;        return null;    }

通過一個實際的例子來示範一下這個過程:

假設我們現在Hashtable的容量為5,已經存在了(5,5),(13,13),(16,16),(17,17),(21,21)這 5 個索引值對,目前他們在Hashtable中的位置如下:

現在,我們插入一個新的索引值對,put(16,22),假設key=16的索引為1.但現在索引1的位置有兩個Entry了,所以程式會對鏈表進行迭代。迭代的過程中,發現其中有一個Entry的key和我們要插入的索引值對的key相同,所以現在會做的工作就是將newValue=22替換oldValue=16,然後返回oldValue=16.

然後我們現在再插入一個,put(33,33),key=33的索引為3,並且在鏈表中也不存在key=33的Entry,所以將該節點插入鏈表的第一個位置。

get 方法

相比較於 put 方法,get 方法則簡單很多。其過程就是首先通過 hash()方法求得 key 的雜湊值,然後根據 hash 值得到 index 索引(上述兩步所用的演算法與 put 方法都相同)。然後迭代鏈表,返回匹配的 key 的對應的 value;找不到則返回 null。

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 遍曆方式

Hashtable 有多種遍曆方式:

//1、使用keys()Enumeration<String> en1 = table.keys();    while(en1.hasMoreElements()) {    en1.nextElement();}//2、使用elements()Enumeration<String> en2 = table.elements();    while(en2.hasMoreElements()) {    en2.nextElement();}//3、使用keySet()Iterator<String> it1 = table.keySet().iterator();    while(it1.hasNext()) {    it1.next();}//4、使用entrySet()Iterator<Entry<String, String>> it2 = table.entrySet().iterator();    while(it2.hasNext()) {    it2.next();}
Hashtable 與 HashMap 的簡單比較

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.