HashTable的實現原理

1、---使用方式---

(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  

  

2、---內部原理---

一、繼承關係

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;  

四、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[]是不重複的  
         * 處理過程:  
         * 一、計算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兩種遍歷方式。

相關文章
相關標籤/搜索