转载请以链接形式标明出处: 本文出自:103style的博客
base on jdk_1.8.0_77
Hashtable
简介Hashtable
的全局变量介绍Hashtable
的构造函数Hashtable
数据操作的函数Hashtable
和HashMap
的异同和 HashMap 一样,Hashtable
也是一个散列表,它存储的内容是键值对。
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable {
Hashtable
继承于 Dictionary
类,实现了 Map
, Cloneable
, java.io.Serializable
接口。
Dictionary
类是任何可将键映射到相应值的类,不过现在已经过时了,新的实现应该实现 Map
接口.
NOTE: This class is obsolete. New implementations should implement the Map interface,
rather than extending this class.
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
VM
允许的最大长度。
private transient HashtableEntry<?,?>[] table;
HashtableEntry
数组,保存hashtable
的数据
private transient int count;
hashtable
的数据个数
private int threshold;
扩容的阈值
private float loadFactor;
加载因子,用于计算扩容的阈值
private transient volatile Set<K> keySet;
volatile
修饰的内存可见的 键的集合
private transient volatile Set<Map.Entry<K,V>> entrySet;
volatile
修饰的内存可见的 键值对 的集合
private transient volatile Collection<V> values;
volatile
修饰的内存可见的 值 的集合
11
,加载因子是 0.75
.public Hashtable() {
this(11, 0.75f);
}
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);
}
public Hashtable(int initialCapacity, float loadFactor) {
//... 对非法的initialCapacity 抛出异常
if (initialCapacity == 0)
initialCapacity = 1;
this.loadFactor = loadFactor;
table = new HashtableEntry<?, ?>[initialCapacity];
threshold = (int) Math.min(initialCapacity, MAX_ARRAY_SIZE + 1);
}
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2 * t.size(), 11), 0.75f);
putAll(t);
}
public synchronized int size()
:public synchronized boolean isEmpty()
:public synchronized Enumeration<K> keys()
:public synchronized boolean contains(Object value)
:public synchronized V get(Object key)
:public synchronized V put(K key, V value)
:public synchronized V remove(Object key)
:public synchronized boolean remove(Object key, Object value)
:public synchronized V replace(K key, V value)
:public synchronized void clear()
:public Set<K> keySet()
:public Set<Map.Entry<K,V>> entrySet()
:public Collection<V> values()
:我们可以发现这些数据操作方法基本都是synchronized
修饰的,没有修饰的三个方法对应的keySet
、entrySet
、values
都是通过volatile
修饰来保证同步的。
所以 Hashtable 是一个线程安全的键值对的集合。
(key.hashCode()& 0x7FFFFFFF) % tab.length
获取 当前 key
在 table
的索引。public synchronized V get(Object key) {
HashtableEntry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return (V)e.value;
}
}
return null;
}
value
是否为null
,为null
则抛出NullPointerException
。(key.hashCode()& 0x7FFFFFFF) % tab.length
获取 当前 key
在 table
的索引。key
对应的节点,找到的话则修改该值,并返回之前的值。如果没找到则通过addEntry
添加节点。table
的阈值,则通过 rehash()
构建一个扩容后长度的数组,并赋值之前的数据。key
value
对应的节点到原链表的头部。public synchronized V put(K key, V value) {
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
HashtableEntry<?, ?>[] tab = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
HashtableEntry<K, V> entry = tab[index];
for (; entry != null; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
addEntry(hash, key, value, index);
return null;
}
private void addEntry(int hash, K key, V value, int index) {
modCount++;
HashtableEntry<?, ?>[] tab = table;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length;
}
@SuppressWarnings("unchecked")
HashtableEntry<K, V> e = tab[index];
tab[index] = new HashtableEntry<>(hash, key, value, e);
count++;
}
protected void rehash() {
int oldCapacity = table.length;
HashtableEntry<?, ?>[] oldMap = table;
int newCapacity = (oldCapacity << 1) + 1;
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
return;
newCapacity = MAX_ARRAY_SIZE;
}
HashtableEntry<?, ?>[] newMap = new HashtableEntry<?, ?>[newCapacity];
modCount++;
threshold = (int) Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap;
for (int i = oldCapacity; i-- > 0; ) {
for (HashtableEntry<K, V> old = oldMap[i]; old != null; ) {
HashtableEntry<K, V> e = old;
old = old.next;
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = newMap[index];
newMap[index] = e;
}
}
}
(key.hashCode()& 0x7FFFFFFF) % tab.length
获取 当前 key
在 table
的索引。null
。public synchronized V remove(Object key) {
HashtableEntry<?, ?>[] tab = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
HashtableEntry<K, V> e = tab[index];
for (HashtableEntry<K, V> prev = null; e != null; prev = e, e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
modCount++;
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
count--;
V oldValue = e.value;
e.value = null;
return oldValue;
}
}
return null;
}
HashTable
基于 Dictionary
类,而 HashMap
是基于AbstractMap
。
Dictionary
是任何可将键映射到相应值的类的抽象父类。
AbstractMap
是基于 Map
接口的实现,它以最大限度地减少实现此接口所需的工作。
HashMap
的 key
和 value
都允许为 null
,而 Hashtable
的 key
和 value
都不允许为 null。
HashMap
遇到 key
为 null
的时候,调用 putForNullKey
方法进行处理,而对 value
没有处理。
Hashtable
遇到 null
,直接返回 NullPointerException
。
Hashtable
方法是同步,而HashMap
则不是。
Hashtable
中的几乎所有的 public
的方法都是 synchronized
的,而有些方法也是在内部通过 synchronized
代码块来实现。所以有人一般都建议如果是涉及到多线程同步时采用 HashTable
,没有涉及就采用 HashMap
,但是在 Collections
类中存在一个静态方法:synchronizedMap()
,该方法创建了一个线程安全的 Map
对象,并把它作为一个封装的对象来返回。
Hashtable
的数据操作方法基本都是通过synchronized
修饰来实现同步的。Hashtable
是一个线程安全的键值对的集合。以上