1. 程式人生 > >Java之HashTable學習

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, float
loadFactor) // 包含“子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是通過"拉鍊法"實現的雜湊表。它包括幾個重要的成員變數:tablecountthresholdloadFactormodCount
  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。

  View Code

說明在詳細介紹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 Code

3.3.2 contains() 和 containsValue()

contains() 和 containsValue() 的作用都是判斷Hashtable是否包含“值(value)”

  View Code

3.3.3 containsKey()

containsKey() 的作用是判斷Hashtable是否包含key

  View Code

3.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 Code

entrySet(), keySet(), keys(), values()的實現方法和elements()差不多,而且原始碼中已經明確的給出了註釋。這裡就不再做過多說明了。

3.3.5 get()

get() 的作用就是獲取key對應的value,沒有的話返回null

  View Code

3.3.6 put()

put() 的作用是對外提供介面,讓Hashtable物件可以通過put()將“key-value”新增到Hashtable中。

  View Code

3.3.7 putAll()

putAll() 的作用是將“Map(t)”的中全部元素逐一新增到Hashtable中

  View Code

3.3.8 remove()

remove() 的作用就是刪除Hashtable中鍵為key的元素

  View Code

 

第3.4部分 Hashtable實現的Cloneable介面

Hashtable實現了Cloneable介面,即實現了clone()方法。
clone()方法的作用很簡單,就是克隆一個Hashtable物件並返回。

  View Code

 

第3.5部分 Hashtable實現的Serializable介面

Hashtable實現java.io.Serializable,分別實現了序列讀取、寫入功能。

序列寫入函式就是將Hashtable的“總的容量,實際容量,所有的Entry”都寫入到輸出流中
序列讀取函式:根據寫入方式讀出將Hashtable的“總的容量,實際容量,所有的Entry”依次讀出

  View Code

 

第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());
}

遍歷測試程式如下

  View Code

 

第5部分 Hashtable示例

下面通過一個例項來學習如何使用Hashtable。

  View Code

(某一次)執行結果

複製程式碼
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
複製程式碼