Java 集合系列-第10篇-Hashtable介紹

Hashtable介紹

和HashMap同樣,Hashtable 也是一個散列表,它存儲的內容是鍵值對(key-value)映射。 Hashtable 繼承於Dictionary,實現了Map、Cloneable、java.io.Serializable接口。 Hashtable 的函數都是同步的,這意味着它是線程安全的。它的key、value都不能夠爲null。此外,Hashtable中的映射不是有序的。html

Hashtable 的實例有兩個參數影響其性能:初始容量 和 加載因子。容量 是哈希表中桶 的數量,初始容量 就是哈希表建立時的容量。注意,哈希表的狀態爲 open:在發生「哈希衝突」的狀況下,單個桶會存儲多個條目,這些條目必須按順序搜索。加載因子 是對哈希表在其容量自動增長以前能夠達到多滿的一個尺度。初始容量和加載因子這兩個參數只是對該實現的提示。關於什麼時候以及是否調用 rehash 方法的具體細節則依賴於該實現。 一般,默認加載因子是 0.75, 這是在時間和空間成本上尋求一種折衷。加載因子太高雖然減小了空間開銷,但同時也增長了查找某個條目的時間(在大多數 Hashtable 操做中,包括 get 和 put 操做,都反映了這一點)。java

Hashtable的構造函數

// 默認構造函數。
public Hashtable() 

// 指定「容量大小」的構造函數
public Hashtable(int initialCapacity) 

// 指定「容量大小」和「加載因子」的構造函數
public Hashtable(int initialCapacity, float loadFactor) 

// 包含「子Map」的構造函數
public Hashtable(Map<? extends K, ? extends V> t)

Hashtable的繼承關係

java.lang.Object
   ↳     java.util.Dictionary<K, V>
         ↳     java.util.Hashtable<K, V>

public class Hashtable<K,V> extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable { }
  • Hashtable繼承於Dictionary類,實現了Map接口。Map是"key-value鍵值對"接口,Dictionary是聲明瞭操做"鍵值對"函數接口的抽象類。算法

  • Hashtable是經過"拉鍊法"實現的哈希表。它包括幾個重要的成員變量:table, count, threshold, loadFactor, modCount。數組

  • table是一個Entry[]數組類型,而Entry實際上就是一個單向鏈表。哈希表的"key-value鍵值對"都是存儲在Entry數組中的。安全

  • count是Hashtable的大小,它是Hashtable保存的鍵值對的數量。函數

  • threshold是Hashtable的閾值,用於判斷是否須要調整Hashtable的容量。threshold的值="容量*加載因子"。性能

  • loadFactor就是加載因子。this

  • modCount是用來實現fail-fast機制的線程

以上參考 http://www.cnblogs.com/skywang12345/p/3310887.htmlcode

Hashtable源碼解析

hashtable 初始化

  • 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 具備相同映射關係的新哈希表。

public Hashtable() {
    this(11, 0.75f);
}

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;
    //private transient Entry<K,V>[] table;
    table = new Entry[initialCapacity];
    // private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    //獲取閾值大小
    threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    //初始化哈希掩碼值。
    initHashSeedAsNeeded(initialCapacity);
}

private static class Entry<K,V> implements Map.Entry<K,V> {
    int hash;
    final K key;
    V value;
    Entry<K,V> next;

    protected Entry(int hash, K key, V value, Entry<K,V> next) {
        this.hash = hash;
        this.key =  key;
        this.value = value;
        this.next = next;
    }

    protected Object clone() {
        return new Entry<>(hash, key, value,
                              (next==null ? null : (Entry<K,V>) next.clone()));
    }

    // Map.Entry Ops

    public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }

    public V setValue(V value) {
        if (value == null)
            throw new NullPointerException();

        V oldValue = this.value;
        this.value = value;
        return oldValue;
    }

    public boolean equals(Object o) {
        if (!(o instanceof Map.Entry))
            return false;
        Map.Entry<?,?> e = (Map.Entry)o;

        return key.equals(e.getKey()) && value.equals(e.getValue());
    }

    public int hashCode() {
        return (Objects.hashCode(key) ^ Objects.hashCode(value));
    }

    public String toString() {
        return key.toString()+"="+value.toString();
    }
}

put方法

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.
    //確保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();

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

    // Creates the new entry.
    Entry<K,V> e = tab[index];
    // 建立新的Entry節點,並將新的Entry插入Hashtable的index位置,並設置e爲新的Entry的下一個元素
    tab[index] = new Entry<>(hash, key, value, e);
    count++;
    return null;
}

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;
    }

isEmpty方法

public synchronized boolean isEmpty() {
        return count == 0;
    }

clear方法

public synchronized void clear方法() {
    Entry tab[] = table;
    modCount++;
    for (int index = tab.length; --index >= 0; )
        tab[index] = null;
    count = 0;
}

contains和containsValue 方法

public boolean containsValue(Object value) {
	return contains(value);
}
public synchronized boolean contains(Object value) {
    if (value == null) {
        throw new NullPointerException();
    }
	//先遍歷數組,在遍歷數組節點
    Entry tab[] = table;
    for (int i = tab.length ; i-- > 0 ;) {
        for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
            if (e.value.equals(value)) {
                return true;
            }
        }
    }
    return false;
}

containsKey方法

public synchronized boolean containsKey(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 true;
        }
    }
    return false;
}

Hashtable 遍歷方式

package basic;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

/**
 * @program: demo
 * @description: demo
 * @author: lee
 * @create: 2018-09-10
 **/
public class Demo {
    public static void main(String[] args) {
        Hashtable hashtable = new Hashtable();
        hashtable.put("123",31231);
        hashtable.put("1423",32);
        Enumeration<String> stringEnumeration = hashtable.keys();
        while (stringEnumeration.hasMoreElements()){
            String key=stringEnumeration.nextElement();
            System.out.println(hashtable.get(key));
        }
        Iterator iterator = hashtable.keySet().iterator();
        while (iterator.hasNext()) {
            Object key = iterator.next();
            System.out.println(hashtable.get(key));
        }

        Iterator iterator1 = hashtable.entrySet().iterator();

        while (iterator1.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator1.next();

            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
    }
}

輸出結果

32
31231
32
31231
1423
32
123
31231
相關文章
相關標籤/搜索