Hashtable概述
- Hashtable是和HashTable一样都是存储key-value数据结构的集合容器
- HashMap不可以存储key和value为null的数据
- 存储key-value的Entry对象实际上是一个单向链表
基本参数
//存储key-value键值对的Entry数组
//Hashtable采用散列法进行存储,每个Entry实际上就是一个单向链表
private transient Entry<K,V>[] table;
//table中的数据总数
private transient int count;
/**
* The table is rehashed when its size exceeds this threshold. (The
* value of this field is (int)(capacity * loadFactor).)
*/
//hashtable rehash的阀值
private int threshold;
//加载因子
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).
*/
//Hashtable被修改的次数,fail-fast
private transient int modCount = 0;
/**
*Hashtable仓位和加载因子的构造器
*
*/
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 = new Entry[initialCapacity];
//阀值为(初始容量与加载因子的乘积)与系统默认阀值中的最小值
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
initHashSeedAsNeeded(initialCapacity);
}
/**
* 默认根据指定初始容量+默认0.75(折中)的构造器
*/
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);
}
//初始容量为11,加载因子为0.75的构造器
public Hashtable() {
this(11, 0.75f);
}
/**
* 参数为一个map的构造器,其中Map的key和value类型分别继承Map<K,V>的K\V类型
* 去参数map即t容量大小的两倍和11中最大的,也就是说,该map最小容量也是11
* 将t中的值全部放入新构造的map中
*/
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2*t.size(), 11), 0.75f);
putAll(t);
}
//table的大小
public synchronized int size() {
return count;
}
//table的容量是否为空
public synchronized boolean isEmpty() {
return count == 0;
}
//返回Hashtable的所有key的枚举对象
public synchronized Enumeration<K> keys() {
return this.<K>getEnumeration(KEYS);
}
//返回Hashtable所有的Values的枚举对象
public synchronized Enumeration<V> elements() {
return this.<V>getEnumeration(VALUES);
}
//是否包含value值
public synchronized boolean contains(Object value) {
if (value == null) {
throw new NullPointerException();
}
Entry tab[] = table;
for (int i = tab.length ; i-- > 0 ;) {
for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
if (e.value.equals(value)) {
return true;
}
}
}
return false;
}
//hashtable是否包含key
public synchronized boolean containsKey(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 true;
}
}
return false;
}
//根据指定key获取对应的value
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容量时,需要重新rehash
protected void rehash() {
//原table大小
int oldCapacity = table.length;
//原table
Entry<K,V>[] oldMap = table;
// overflow-conscious code
//扩容后的大小
int newCapacity = (oldCapacity << 1) + 1;
//如果扩容后的大小大于最大值,则取最大值
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
// Keep running with MAX_ARRAY_SIZE buckets
return;
newCapacity = MAX_ARRAY_SIZE;
}
//新建map用于rehash后存储数据
Entry<K,V>[] newMap = new Entry[newCapacity];
//用于标记Hashtable被修改的次数+1
modCount++;
//修改阀值的大小,新容器大小乘加载因子和允许最大容量中取较小值
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
// TODO
boolean rehash = initHashSeedAsNeeded(newCapacity);
//将表的指针指向新建的map地址
table = newMap;
//遍历原table,将值重新hash后计算出新的index,放入新的table中, 从后向前进行插入
for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
Entry<K,V> e = old;
//同一个index上的(hash值相同)的数据
old = old.next;
if (rehash) {
e.hash = hash(e.key);
}
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = newMap[index];
newMap[index] = e;
}
}
}
/**
* Maps the specified <code>key</code> to the specified
* <code>value</code> in this hashtable. Neither the key nor the
* value can be <code>null</code>. <p>
* 将KEY对应的value放入hashtabl中。KEY和VALUE都不能为空
*/
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
//如果KEY已经存在,则value进行覆盖
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;
}
}
//修改表示进行+1
modCount++;
//如果容器总的数量已经达到阀值,则进行rehash操作
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
hash = hash(key);
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
//创建新的Entry用于存放新的KEY-VALUE键值对
Entry<K,V> e = tab[index];
tab[index] = new Entry<>(hash, key, value, e);
//容量进行+1
count++;
//如果KEY已经存在则返回原KEY对应的value,否则返回NULL
return null;
}
/**
* Removes the key (and its corresponding value) from this
* hashtable. This method does nothing if the key is not in the hashtable.
* 将该hashtable中的KEY以及对应的value进行删除
*/
public synchronized V remove(Object key) {
//先拿到this的hashtable
Entry tab[] = table;
//对key进行hash操作,获取该KY对应的index
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
//如果该index有多个entry,则进行遍历寻找后进行删除
for (Entry<K,V> e = tab[index], 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;
//help GC
e.value = null;
return oldValue;
}
}
return null;
}
/**
* Clears this hashtable so that it contains no keys.
* 清除hashtable中的数据
*/
public synchronized void clear() {
Entry tab[] = table;
modCount++;
for (int index = tab.length; --index >= 0; )
tab[index] = null;
count = 0;
}
参考
http://www.cnblogs.com/xingele0917/p/3815370.html
http://www.cnblogs.com/jilodream/
https://www.cnblogs.com/skywang12345/p/3310887.html
http://www.importnew.com/24822.html
网友评论