文章均为本人技术笔记,转载请注明出处https://segmentfault.com/u/yzwalljava
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializablesegmentfault
Hashtable和HashMap同样也是散列表,存储元素也是键值对;
Hashtable继承于Dictionary类(Dictionary类声明了操做键值对的接口方法),实现Map接口(定义键值对接口);
Hashtable大部分类用synchronized
修饰,证实Hashtable是线程安全的;数组
private transient Entry<?,?>[] table
:键值对/Entry数组,每一个Entry本质上是一个单向链表的表头安全
private int threshold
:rehash阈值数据结构
private float loadFactor
:装填因子函数
private transient int modCount = 0
: Hashtable结构化修改次数,用来实现fail-fast机制;线程
private transient volatile Set<Map.Entry<K,V>> entrySet
:Hastable视图,键值对集合;code
private transient volatile Set<K> keySet
:Hastable视图,key集,Hashtable中key不可重复;继承
private transient volatile Collection<V> values
:Hastable视图,value集合,可重复;索引
Hashtable中key和value是一对多关系;
private static class Entry<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Entry<K, V> next; ... // 计算键值对的hashCode public int hashCode() { // "^" 按位异或, hash在调用构造器时传入 return hash ^ Objects.hashCode(value); } }
键值对
public boolean containsValue(Object value)
内部调用contains(value)
;
判断是否含有该value的键值对,在Hashtable中hashCode相同的Entry用链表组织,hashCode不一样的存储在Entry数组table中;
// in contains() method. Entry<?,?> tab[] = table; // 查找:遍历全部Entry链表 for (int i = tab.length ; i-- > 0 ;) { for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) { if (e.value.equals(value)) { return true; } } } return false;
int index = (hash & 0x7FFFFFFF) % tab.length;
计算键值对的桶位(本质是键值对在tab数组中的索引),Hashtable本质上采用除数取余法进行散列分布,模运算效率较低
int hash = key.hashCode()
Hashtable直接调用key的hashCode()计算hashCode;
Entry<?,?> tab[] = table; int hash = key.hashCode(); /** * 计算index, % tab.length防止数组越界 * index表示key对应entry所在链表表头 */ int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return true; } } return false;
public synchronized V get(Object key)
:根据指定key查找对应value,查找原理与containsKey相同,查找成功返回value,不然返回null;
设置键值对,key和value都不可为null,设置顺序:
若是Hashtable含有key,设置(key, oldValue) -> (key, newValue);
若是Hashtable不含有key, 调用addEntry(...)
添加新的键值对;
当键值对个数超过阈值,先进行rehash而后添加entry,不然直接添加entry;
remove操做,计算key所在链表表头table[index],而后进行单向链表的节点删除操做
对Hashtable的浅拷贝操做,浅拷贝全部bucket(单向链表组织形式)的表头;
当Hashtable中键值对总数超过阈值(容量*装载因子)后,内部自动调用rehash()增长容量,从新计算每一个键值对的hashCode;int newCapacity = (oldCapacity << 1) + 1
计算新容量 = 2 * 旧容量 + 1;而且根据新容量更新阈值;
... for (int i = oldCapacity ; i-- > 0 ;) { // 拷贝每一个Entry链表 for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) { Entry<K,V> e = old; old = old.next; // 从新计算每一个Entry链表的表头索引(rehash) int index = (e.hash & 0x7FFFFFFF) % newCapacity; // 开辟链表节点 e.next = (Entry<K,V>)newMap[index]; // 拷贝 newMap[index] = e; } }