1、特点:
(1)、线程安全 使用的是synchronized关键字,给hashTable对象加互斥锁;
(2)、 以键值对<k,v>的形式储存
(3)、键和值都不能为null;
(4)、插入无序
2、数据结构:数组+链表
3、底层源码分析:
(1)继承关系:
继承 Dictionary<K,V> , 实现了 Map<K,V>, Cloneable, java.io.Serializable
(2)构造函数:(四个)
注意点1、在建立hashTable对象时底层数组直接被初始化,
注意点2、如果传入的容量大小为0,则初始化时会自动调整为1 ;
(3)默认值 :
默认初始容量 11 , 默认初始负载因子:0.75
(4)增长方式:
扩容临界: 当前size >= 扩容阈值(当前容量 * 负载因子)
rehash方法, 2倍+1 )
(5)基本属性:
Entry[] table; //数组
int count;//元素个数
float loadFactor; //加载因子
int threshold; // 阈值
class Entry{} //内部类
(6)增添查改
A、添加元素**************************************
首先判断value == null?是则抛异常,否则下一步
利用key的hashCode重新hash计算出当前对象的元素在数组中的下标
存储时,如果出现hash值相同的key,此时有两种情况(用equals比较)。
(1)如果key相同,则覆盖原始值;
(2)如果key不同(出现冲突),则将当前的key-value放入链表头部;
容量检查,如果超过阈值,就进行扩容,并重新计算该下标;
如果数组下标处为null,直接新街Entry放入此处;
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 = key.hashCode();
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)) {
V old = e.value;
e.value = value;
return old;
}
}
modCount++;
if (count >= threshold) {
// 达到临界数目时扩容
rehash();
tab = table;
index = (hash & 0x7FFFFFFF) % tab.length;
}
//如果数组当前索引位置为null,创建新的Entry,放到当前位置。
Entry<K,V> e = tab[index];
tab[index] = new Entry<K,V>(hash, key, value, e);
count++;
return null;
}
B、获取元素 *************************************
获取key的hash值,然后计算对应的索引位置;
遍历当前索引位置下的链表,如果入参key == 链表中某个元素的Key,返回该元素的value;
否则返回null;
public synchronized V get(Object key) {
Entry tab[] = table;
int hash = key.hashCode();
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;
}
C、删除元素 *************************************
获取入参key的hash值,计算下标;
在数组指定下标处开始遍历(key==nulltable[0]处遍历查找);
遍历判断 入参 key equals (entry.key)? 是则返回此元素,然后返回其value。
public synchronized V remove(Object key) {
Entry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
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;
e.value = null;
return oldValue;
}
}
return null;
}
4、方法探究
5、HashTable和HashMap的异同
不同点:
(1)主要:HashTable 的线程安全,效率低;
HashMap 的线程不安全,效率高;
(2) 继承关系:HashTable继承dictionary
HashMap继承AbstractMap
(3) null值:HashTable 键和值都不能为null;
HashMap键可以有一个null,值可以有多个null
(4)初始化容量:hashTable的初始化容量为11;
HashMap的初始化容量为16;
(5)扩容倍数:
HashMap:2倍扩容
HashTable:2倍+1
(6)获得hash值计算方式不同;
相同点:
底层数据结构相同;
key不能重复
无序;