一、---使用方式---
(1)Hashtable 是一個散列表,它存儲的內容是鍵值對(key-value)映射。
(2)Hashtable 繼承於Dictionary,實現了Map、Cloneable、java.io.Serializable接口。
(3)Hashtable 的函數都是同步的,這意味着它是線程安全的。它的key、value都不可以為null。
如下是Hashtable 的簡單使用方式:在遍歷時使用是三種遍歷方式來對其進行遍歷
package ThreeWeek;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public class HashTableTest {
public static void main(String args[]){
Hashtable<String, Integer> table = new Hashtable<String, Integer>();
//[1]添加元素
table.put("zhangsan", 22);
table.put("lisi", 33);
table.put("wangwu", 44);
//[2]toString()方式打印
System.out.println(table.toString());
//[3]Iterator遍歷方式1--鍵值對遍歷entrySet()
Iterator<Entry<String, Integer>> iter = table.entrySet().iterator();
while(iter.hasNext()){
Map.Entry<String, Integer> entry = (Map.Entry<String, Integer>)iter.next();
String key = entry.getKey();
int value = entry.getValue();
System.out.println("entrySet:"+key+" "+value);
}
System.out.println("====================================");
//[4]Iterator遍歷方式2--key鍵的遍歷
Iterator<String> iterator = table.keySet().iterator();
while(iterator.hasNext()){
String key = (String)iterator.next();
int value = table.get(key);
System.out.println("keySet:"+key+" "+value);
}
System.out.println("====================================");
//[5]通過Enumeration來遍歷Hashtable
Enumeration<String> enu = table.keys();
while(enu.hasMoreElements()) {
System.out.println("Enumeration:"+table.keys()+" "+enu.nextElement());
}
}
}
輸出:
{zhangsan=22, lisi=33, wangwu=44}
entrySet:zhangsan 22
entrySet:lisi 33
entrySet:wangwu 44
====================================
keySet:zhangsan 22
keySet:lisi 33
keySet:wangwu 44
====================================
Enumeration:java.util.Hashtable$Enumerator@139a55 zhangsan
Enumeration:java.util.Hashtable$Enumerator@1db9742 lisi
Enumeration:java.util.Hashtable$Enumerator@106d69c wangwu
二、---內部原理---
1、繼承關系
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 { }
與HashMap不同的是Hashtable是繼承Dictionary,實現了Map接口。Map是"key-value鍵值對"接口,Dictionary是聲明了操作"鍵值對"函數接口的抽象類。
2、構造函數
(1)Hashtable中提供了四個構造函數,如下:
// 默認構造函數。 public Hashtable() // 指定“容量大小”的構造函數 public Hashtable(int initialCapacity) // 指定“容量大小”和“加載因子”的構造函數 public Hashtable(int initialCapacity, float loadFactor) // 包含“子Map”的構造函數 public Hashtable(Map<? extends K, ? extends V> t)
(2)上面的四個構造方法中,第三個是最重要的,指定初始化容量和構造因子
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,獲得大小為initialCapacity的table數組
table = new Entry[initialCapacity];
//計算閥值
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
//初始化HashSeed值
initHashSeedAsNeeded(initialCapacity);
}
3、成員變量
(1)table是一個Entry[]數組類型,而Entry實際上就是一個單向鏈表。哈希表的"key-value鍵值對"都是存儲在Entry數組中的。
(2)count是Hashtable的大小,它是Hashtable保存的鍵值對的數量。
(3)threshold是Hashtable的閾值,用於判斷是否需要調整Hashtable的容量。threshold的值="容量*加載因子"。
(4)loadFactor就是加載因子。
(5)modCount是用來實現fail-fast機制的
private transient Entry[] table; // Hashtable中元素的實際數量 private transient int count; // 閾值,用於判斷是否需要調整Hashtable的容量(threshold = 容量*加載因子) private int threshold; // 加載因子 private float loadFactor; // Hashtable被改變的次數 private transient int modCount = 0;
4、put和get方法
(1)put方法
從下面的代碼中我們可以看出,Hashtable中的key和value是不允許為空的,當我們想要想Hashtable中添加元素的時候,首先計算key的hash值,然
后通過hash值確定在table數組中的索引位置,最后將value值替換或者插入新的元素,如果容器的數量達到閾值,就會進行擴充。
public synchronized V put(K key, V value) {
// 確保value不為null
if (value == null) {
throw new NullPointerException();
}
/*
* 確保key在table[]是不重復的
* 處理過程:
* 1、計算key的hash值,確認在table[]中的索引位置
* 2、迭代index索引位置,如果該位置處的鏈表中存在一個一樣的key,則替換其value,返回舊值
*/
Entry tab[] = table;
int hash = hash(key); //計算key的hash值
int index = (hash & 0x7FFFFFFF) % tab.length; //確認該key的索引位置
//迭代,尋找該key,替換
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();
tab = table;
hash = hash(key);
index = (hash & 0x7FFFFFFF) % tab.length;
}
// 在索引位置處插入一個新的節點
Entry<K,V> e = tab[index];
tab[index] = new Entry<>(hash, key, value, e);
//容器中元素+1
count++;
return null;
}
(2)get方法
同樣也是先獲得索引值,然后進行遍歷,最后返回
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和HashMap到底有哪些不同呢
(1)基類不同:HashTable基於Dictionary類,而HashMap是基於AbstractMap。Dictionary是什么?它是任何可將鍵映射到相應值的類的抽象父類,而AbstractMap是基於Map接口的骨干實現,它以最大限度地減少實現此接口所需的工作。
(2)null不同:HashMap可以允許存在一個為null的key和任意個為null的value,但是HashTable中的key和value都不允許為null。
(3)線程安全:HashMap時單線程安全的,Hashtable是多線程安全的。
(4)遍歷不同:HashMap僅支持Iterator的遍歷方式,Hashtable支持Iterator和Enumeration兩種遍歷方式。
