源码
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable{}
从源码中可知,HashTable 继承与 Dictionary 类,同时实现了 Map 、Cloneable、Serializable接口。Dictionary 类是任何可将键映射到相应值得类 (如 Hashtable)的抽象父类。每个键和值都是对象。
Dictionary源码
public abstract class Dictionary<K,V>
extends Object
成员变量:
Hashtable是通过”拉链法”实现的哈希表。它包括几个重要的成员变量:table, count, threshold, loadFactor, modCount
/**
* table是一个 Entry[] 数组类型,哈希表的"key-value键值对"都是存储在Entry数组中的
*/
private transient Entry<?,?>[] table;
/**
* count 是 Hashtable 的大小,它是 Hashtable 保存的键值对的数量
*/
private transient int count;
/**
* threshold 是 Hashtable 的阈值,用于判断是否需要调整 Hashtable 的容量。threshold 的值="容量*加载因子"
*
* @serial
*/
private int threshold;
/**
* 加载因子.
*
* @serial
*/
private float loadFactor;
/**
* The number of times this Hashtable has been structurally modified
* Structural modifications are those that change the number of entries in
* the Hashtable or otherwise modify its internal structure (e.g.,
* rehash). This field is used to make iterators on Collection-views of
* the Hashtable fail-fast. (See ConcurrentModificationException).
*/
private transient int modCount = 0;
构造方法
Hashtable()
构造一个空的哈希表,其中有默认初始容量(11)和加载因子(0.75)。.
Hashtable(int initialCapacity)
使用指定的初始容量和默认加载因子(0.75)构造一个新的哈希表。
Hashtable(int initialCapacity, float loadFactor)
使用指定的初始容量和指定的负载因素构造一个新的hashtable。
Hashtable(Map<? extends K,? extends V> t)
使用与给定映射相同的映射构造一个新的哈希表
put 方法
判断 value 是否为空,为空则抛出异常;
计算 key 的 hash 值,并根据 hash 值获得 key 在 table 数组中的位置 index,如果 table[index] 元素不为空,则进行迭代,如果遇到相同的 key,则直接替换,并返回旧 value;
否则,我们可以将其插入到 table[index] 位置。
public V put(K key,V value)
将指定的键映射到这个散列表中指定的值。键值和值都不能为空。通过使用与原始密钥相同的键调用get方法,可以检索该值。
指定:
put in interface Map<K,V>
put in class Dictionary<K,V>
参数:
key - 键
value - 值
返回:
在这个散列表中指定的键的前一个值,如果没有一个键值,则为null
异常:
NullPointerException - 如果键值为null
get 方法
相比较于 put 方法,get 方法则简单很多。其过程就是首先通过 hash()方法求得 key 的哈希值,然后根据 hash 值得到 index 索引(上述两步所用的算法与 put 方法都相同)。然后迭代链表,返回匹配的 key 的对应的 value;找不到则返回 null
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、HashMap 的 key 和 value 都允许为 null,而 Hashtable 的 key 和 value 都不允许为 null。HashMap 遇到 key 为 null 的时候,调用 putForNullKey 方法进行处理,而对 value 没有处理;Hashtable遇到 null,直接返回 NullPointerException。
3、Hashtable 方法是同步,而HashMap则不是。我们可以看一下源码,Hashtable 中的几乎所有的 public 的方法都是 synchronized 的,而有些方法也是在内部通过 synchronized 代码块来实现。所以有人一般都建议如果是涉及到多线程同步时采用 HashTable,没有涉及就采用 HashMap,但是在 Collections 类中存在一个静态方法:synchronizedMap(),该方法创建了一个线程安全的 Map 对象,并把它作为一个封装的对象来返回。