Hashtable 原理相關

問:談談你對 Hashtable 原理的理解?

答:Hashtable 與 HashMap 類似,也是一個存儲鍵值對的散列表,Hashtable 繼承自 Dictionary 類,實現了 Map、Cloneable、Serializable 接口,Hashtable 是通過拉鏈法實現哈希表的,其構造方法主要有四個,如下:

        //默認構造方法,容量為 11,加載因子為 0.75 
    public Hashtable()
        //通過指定初始容量與默認加載因子 (0.75) 構造一個新的空哈希表
    public Hashtable( int initialCapacity )
        // 構造一個給定 Map 的新哈希表
    public Hashtable(Map < ? extends K , ? extends V > t )
        // 通過指定初始容量和指定加載因子構造一個新的空哈希表 
    public Hashtable( int initialCapacity, float loadFactor )
  • Hashtable 的并發安全 put 原理是先判斷 value 是否為空,為空則拋出異常,然后計算 key 的 hash 值(key.hashCode()),如果 key 為空則拋出異常,否則根據 hash 值獲得 key 在 table 數組中的位置 index,接著如果 table[index] 元素不為空,則進行迭代,如果遇到相同的 key,則直接替換,并返回舊 value,否則,我們可以將其插入到 table[index] 位置(發生哈希碰撞時變為鏈表頭,否則該數組位置單個元素);整體看來和 HashMap 十分相似,算是精簡版的 HashMap put 原理,具體源碼分析如下:
//put方法是通過synchronized保證單操作并發安全的
    public synchronized V put(K key, V value) {
        
// Hashtable的value不允許為空!!! 
        if (value == null) {
            throw new NullPointerException();
        }
        // Makes sure the key is not already in the hashtable.
        HashtableEntry tab[] = table;
        //hash方法的實質是key.hashCode(),所以Hashtable的key也不允許為空!!! 
        int hash = hash(key);
        // 依據key的hash值計算出index值來確定其在table[]中的位置 
        int index = (hash & 0x7FFFFFFF) % tab.length;
        // 迭代index索引位置的鏈表,如果該位置處的鏈表存在相同的key,
        // 則替換value,返回舊的value
        for (HashtableEntry<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操作 
            rehash();
            tab = table;
            hash = hash(key);
            index = (hash & 0x7FFFFFFF) % tab.length;
        }
        //插入后返回的為null
        HashtableEntry<K, V> e = tab[index];
        //創建新的 Entry 節點,并將新的 Entry 插入 Hashtable 的 index 位置,
        // 并設置 e 為新的 Entry 的下一個元素 
        tab[index] = new HashtableEntry<>(hash, key, value, e);
        count++;
        return null;
    }

    private static int hash(Object k) {
        return k.hashCode();
    }
  • Hashtable 的并發安全 get 方法原理是先通過 hash()方法求得 key 的哈希值,然后根據 hash 值得到 index 索引,然后迭代鏈表,返回匹配的 key 對應的 value,如果找不到則返回 null,源碼如下:
        public synchronized V get (Object key ){
            HashtableEntry tab[] = table;
            int hash = hash(key);
            int index = (hash & 0x7FFFFFFF) % tab.length;
            for (HashtableEntry<K, V> e = tab[index]; e != null; e = e.next) {
                if ((e.hash == hash) && e.key.equals(key)) {
                    return e.value;
                }
            }
            return null;
        }
問:說說為什么 Hashtable 的 key、value 都不允許為 null,而類似實現的 HashMap 就可以?

答:因為 Hashtable 比 HashMap 先出來,且 Hashtable 繼承自 Dictionary 類,Dictionary 抽象層的 put 方法定義是不允許 key、value 為空的,也就是說設計者當初就沒考慮 null 情況,而后來 HashMap 卻考量了這種情況;此外由于 Hashtable 在 put 實現時沒有對 key 進行判斷,獲取 key 的哈希值是直接通過 key.hashCode() 方法獲取的,所以 key 如果為空就崩潰了,而 value 是直接防御性實現的,而對于 HashMap 來說對于 key、value 為空都進行了單獨處理。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。