1. 程式人生 > >HashTable的實現原理

HashTable的實現原理

數量 serializa 機制 public mod load void wan AI

一、---使用方式---

(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兩種遍歷方式。

HashTable的實現原理