HashTable的实现原理

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

(1)Hashtable 是一个散列表,它存储的内容是键值对(key-value)映射。

(2)Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。

(3)Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。

如下是Hashtable 的简单使用方式:在遍历时使用是三种遍历方式来对其进行遍历

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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()); 
        }  
               
    

  

输出:

1
2
3
4
5
6
7
8
9
10
11
12
{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、继承关系

1
2
3
4
5
6
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中提供了四个构造函数,如下:

1
2
3
4
5
6
7
8
9
10
11
// 默认构造函数。 
public Hashtable()  
   
// 指定“容量大小”的构造函数 
public Hashtable(int initialCapacity)  
   
// 指定“容量大小”和“加载因子”的构造函数 
public Hashtable(int initialCapacity, float loadFactor)  
   
// 包含“子Map”的构造函数 
public Hashtable(Map<? extends K, ? extends V> t)

(2)上面的四个构造方法中,第三个是最重要的,指定初始化容量和构造因子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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机制的

1
2
3
4
5
6
7
8
9
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值替换或者插入新的元素,如果容器的数量达到阈值,就会进行扩充。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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方法

同样也是先获得索引值,然后进行遍历,最后返回

1
2
3
4
5
6
7
8
9
10
11
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两种遍历方式。

 

posted @   森林木马  阅读(2488)  评论(0)    收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示