Java之HashTable學習
概要
前一章,我們學習了HashMap。這一章,我們對Hashtable進行學習。
我們先對Hashtable有個整體認識,然後再學習它的原始碼,最後再通過例項來學會使用Hashtable。
第1部分 Hashtable介紹
第2部分 Hashtable資料結構
第3部分 Hashtable原始碼解析(基於JDK1.6.0_45)
第4部分 Hashtable遍歷方式
第5部分 Hashtable示例
轉載請註明出處:http://www.cnblogs.com/skywang12345/p/3310887.html
第1部分 Hashtable介紹
Hashtable 簡介
和HashMap一樣,Hashtable 也是一個散列表,它儲存的內容是鍵值對(key-value)對映。
Hashtable 繼承於Dictionary,實現了Map、Cloneable、java.io.Serializable介面。
Hashtable 的函式都是同步的,這意味著它是執行緒安全的。它的key、value都不可以為null。此外,Hashtable中的對映不是有序的。
Hashtable 的例項有兩個引數影響其效能:初始容量 和 載入因子。容量 是雜湊表中桶 的數量,初始容量 就是雜湊表建立時的容量。注意,雜湊表的狀態為 open:在發生“雜湊衝突”的情況下,單個桶會儲存多個條目,這些條目必須按順序搜尋。載入因子 是對雜湊表在其容量自動增加之前可以達到多滿的一個尺度。初始容量和載入因子這兩個引數只是對該實現的提示。關於何時以及是否呼叫 rehash 方法的具體細節則依賴於該實現。
通常,預設載入因子是 0.75, 這是在時間和空間成本上尋求一種折衷。載入因子過高雖然減少了空間開銷,但同時也增加了查詢某個條目的時間(在大多數 Hashtable 操作中,包括 get 和 put 操作,都反映了這一點)。
Hashtable的建構函式
// 預設建構函式。 public Hashtable() // 指定“容量大小”的建構函式 public Hashtable(int initialCapacity) // 指定“容量大小”和“載入因子”的建構函式 public Hashtable(int initialCapacity, floatloadFactor) // 包含“子Map”的建構函式 public Hashtable(Map<? extends K, ? extends V> t)
Hashtable的API
synchronized void clear() synchronized Object clone() boolean contains(Object value) synchronized boolean containsKey(Object key) synchronized boolean containsValue(Object value) synchronized Enumeration<V> elements() synchronized Set<Entry<K, V>> entrySet() synchronized boolean equals(Object object) synchronized V get(Object key) synchronized int hashCode() synchronized boolean isEmpty() synchronized Set<K> keySet() synchronized Enumeration<K> keys() synchronized V put(K key, V value) synchronized void putAll(Map<? extends K, ? extends V> map) synchronized V remove(Object key) synchronized int size() synchronized String toString() synchronized Collection<V> values()
第2部分 Hashtable資料結構
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與Map關係如下圖:
從圖中可以看出:
(01) Hashtable繼承於Dictionary類,實現了Map介面。Map是"key-value鍵值對"介面,Dictionary是聲明瞭操作"鍵值對"函式介面的抽象類。
(02) Hashtable是通過"拉鍊法"實現的雜湊表。它包括幾個重要的成員變數:table, count, threshold, loadFactor, modCount。
table是一個Entry[]陣列型別,而Entry實際上就是一個單向連結串列。雜湊表的"key-value鍵值對"都是儲存在Entry陣列中的。
count是Hashtable的大小,它是Hashtable儲存的鍵值對的數量。
threshold是Hashtable的閾值,用於判斷是否需要調整Hashtable的容量。threshold的值="容量*載入因子"。
loadFactor就是載入因子。
modCount是用來實現fail-fast機制的
第3部分 Hashtable原始碼解析(基於JDK1.6.0_45)
為了更瞭解Hashtable的原理,下面對Hashtable原始碼程式碼作出分析。
在閱讀原始碼時,建議參考後面的說明來建立對Hashtable的整體認識,這樣更容易理解Hashtable。
說明: 在詳細介紹Hashtable的程式碼之前,我們需要了解:和Hashmap一樣,Hashtable也是一個散列表,它也是通過“拉鍊法”解決雜湊衝突的。
第3.1部分 Hashtable的“拉鍊法”相關內容
3.1.1 Hashtable資料儲存陣列
private transient Entry[] table;
Hashtable中的key-value都是儲存在table陣列中的。
3.1.2 資料節點Entry的資料結構
View Code 從中,我們可以看出 Entry 實際上就是一個單向連結串列。這也是為什麼我們說Hashtable是通過拉鍊法解決雜湊衝突的。
Entry 實現了Map.Entry 介面,即實現getKey(), getValue(), setValue(V value), equals(Object o), hashCode()這些函式。這些都是基本的讀取/修改key、value值的函式。
第3.2部分 Hashtable的建構函式
Hashtable共包括4個建構函式
View Code
第3.3部分 Hashtable的主要對外介面
3.3.1 clear()
clear() 的作用是清空Hashtable。它是將Hashtable的table陣列的值全部設為null
View Code3.3.2 contains() 和 containsValue()
contains() 和 containsValue() 的作用都是判斷Hashtable是否包含“值(value)”
View Code3.3.3 containsKey()
containsKey() 的作用是判斷Hashtable是否包含key
View Code3.3.4 elements()
elements() 的作用是返回“所有value”的列舉物件
View Code 從中,我們可以看出:
(01) 若Hashtable的實際大小為0,則返回“空列舉類”物件emptyEnumerator;
(02) 否則,返回正常的Enumerator的物件。(Enumerator實現了迭代器和列舉兩個介面)
我們先看看emptyEnumerator物件是如何實現的
View Code我們在來看看Enumeration類
Enumerator的作用是提供了“通過elements()遍歷Hashtable的介面” 和 “通過entrySet()遍歷Hashtable的介面”。因為,它同時實現了 “Enumerator介面”和“Iterator介面”。
View CodeentrySet(), keySet(), keys(), values()的實現方法和elements()差不多,而且原始碼中已經明確的給出了註釋。這裡就不再做過多說明了。
3.3.5 get()
get() 的作用就是獲取key對應的value,沒有的話返回null
View Code3.3.6 put()
put() 的作用是對外提供介面,讓Hashtable物件可以通過put()將“key-value”新增到Hashtable中。
View Code3.3.7 putAll()
putAll() 的作用是將“Map(t)”的中全部元素逐一新增到Hashtable中
View Code3.3.8 remove()
remove() 的作用就是刪除Hashtable中鍵為key的元素
View Code
第3.4部分 Hashtable實現的Cloneable介面
Hashtable實現了Cloneable介面,即實現了clone()方法。
clone()方法的作用很簡單,就是克隆一個Hashtable物件並返回。
第3.5部分 Hashtable實現的Serializable介面
Hashtable實現java.io.Serializable,分別實現了序列讀取、寫入功能。
序列寫入函式就是將Hashtable的“總的容量,實際容量,所有的Entry”都寫入到輸出流中
序列讀取函式:根據寫入方式讀出將Hashtable的“總的容量,實際容量,所有的Entry”依次讀出
第4部分 Hashtable遍歷方式
4.1 遍歷Hashtable的鍵值對
第一步:根據entrySet()獲取Hashtable的“鍵值對”的Set集合。
第二步:通過Iterator迭代器遍歷“第一步”得到的集合。
// 假設table是Hashtable物件 // table中的key是String型別,value是Integer型別 Integer integ = null; Iterator iter = table.entrySet().iterator(); while(iter.hasNext()) { Map.Entry entry = (Map.Entry)iter.next(); // 獲取key key = (String)entry.getKey(); // 獲取value integ = (Integer)entry.getValue(); }
4.2 通過Iterator遍歷Hashtable的鍵
第一步:根據keySet()獲取Hashtable的“鍵”的Set集合。
第二步:通過Iterator迭代器遍歷“第一步”得到的集合。
// 假設table是Hashtable物件 // table中的key是String型別,value是Integer型別 String key = null; Integer integ = null; Iterator iter = table.keySet().iterator(); while (iter.hasNext()) { // 獲取key key = (String)iter.next(); // 根據key,獲取value integ = (Integer)table.get(key); }
4.3 通過Iterator遍歷Hashtable的值
第一步:根據value()獲取Hashtable的“值”的集合。
第二步:通過Iterator迭代器遍歷“第一步”得到的集合。
// 假設table是Hashtable物件 // table中的key是String型別,value是Integer型別 Integer value = null; Collection c = table.values(); Iterator iter= c.iterator(); while (iter.hasNext()) { value = (Integer)iter.next(); }
4.4 通過Enumeration遍歷Hashtable的鍵
第一步:根據keys()獲取Hashtable的集合。
第二步:通過Enumeration遍歷“第一步”得到的集合。
Enumeration enu = table.keys(); while(enu.hasMoreElements()) { System.out.println(enu.nextElement()); }
4.5 通過Enumeration遍歷Hashtable的值
第一步:根據elements()獲取Hashtable的集合。
第二步:通過Enumeration遍歷“第一步”得到的集合。
Enumeration enu = table.elements(); while(enu.hasMoreElements()) { System.out.println(enu.nextElement()); }
遍歷測試程式如下:
第5部分 Hashtable示例
下面通過一個例項來學習如何使用Hashtable。
(某一次)執行結果:
table:{two=5, one=0, three=6} next : two - 5 next : one - 0 next : three - 6 size:3 contains key two : true contains key five : false contains value 0 : true table:{two=5, one=0} table is empty