(1)Hashtable 是一個散列表,它存儲的內容是鍵值對(key-value)映射。java
(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
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是聲明瞭操做"鍵值對"函數接口的抽象類。 this
(1)Hashtable中提供了四個構造函數,以下:線程
// 默認構造函數。 public Hashtable() // 指定「容量大小」的構造函數 public Hashtable(int initialCapacity) // 指定「容量大小」和「加載因子」的構造函數 public Hashtable(int initialCapacity, float loadFactor) // 包含「子Map」的構造函數 public Hashtable(Map<? extends K, ? extends V> t)
(2)上面的四個構造方法中,第三個是最重要的,指定初始化容量和構造因子blog
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); }
(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;
(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[]是不重複的 * 處理過程: * 一、計算key的hash值,確認在table[]中的索引位置 * 二、迭代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兩種遍歷方式。