一、---使用方式---
(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 { }
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;
(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两种遍历方式。