HashTable的特点
HashTable继承自Dictionary类,Dictionary 类是一个抽象类,在JDK 1.0中提供用来存储键/值对,作用和Map类相似。

HashTable类中,其数据结构与HashMap是相同的。依然是采用“链地址法”实现的哈希表,保存实际数据的,依然是Entry对象。
Entry<K,V> implements Map.Entry<K,V> {
int hash;
final K key;
V value;
Entry<K,V> next;
}
和HashMap很类似
不同点:
1、HashTable是线程安全的(synchronized),HashMap线程不安全
2、HashTable是key和value不能为null,而HashMap允许key和value为空。
3、使用的迭代器不同,Hashtable的迭代器(enumerator)。
put方法
put方法的主要逻辑如下:
1. 先获取synchronized锁。
2. put方法不允许null值,如果发现是null,则直接抛出异常(key和value都不能为null)。
3. 计算key的哈希值和index
4. 遍历对应位置的链表,如果发现已经存在相同的hash和key,则更新value,并返回旧值。
5. 如果不存在相同的key的Entry节点,则增加节点。在新增节点时,考虑是否需要扩容,如果需要则进行扩容,之后添加新节点到链表头部。
rehash扩容方法
数组长度增加一倍((oldCapacity << 1) + 1)(如果超过上限,则设置成上限值)。
更新哈希表的扩容限值。
遍历旧表中的节点,计算在新表中的index,插入到对应位置链表的头部
get方法
1. 先获取synchronized锁。
2. 计算key的哈希值和index。
3. 在对应位置的链表中寻找具有相同hash和key的节点,返回节点的value。
4. 如果遍历结束都没有找到节点,则返回null。
remove方法
1. 先获取synchronized锁。
2. 计算key的哈希值和index。
3. 在对应位置的链表中寻找具有相同hash和key的节点,将该key对应的节点从当前链表中删除。
4. 如果遍历结束都没有找到节点,则返回null。
LinkedHashMap

继承自HashMap。
适用场景:
存储的数据是键值对,且需要保证数据按插入顺序有序的话需要使用LinkedHashMap。
数据存储结构

重写了void init()方法:
void init() {
//创建了一个hash=-1,key,value,next都为null的Entry
header = new Entry<>(-1, null, null, null);
//让创建的Entry的before和after都指向自身(其实就是创建了一个职业头部节点的双向链表)
header.before = header.after = header;
}
属性:accessOrder (默认是false)
true:按照访问顺序组织数据
false: 按照插入顺序组织数据
当accessOrder属性为默认时,进行get操作:


当accessOrder属性为true时,进行get操作:(会按照访问得顺序重新排列)


put方法(重要)
它么有重写put方法,只是重写了 void addEntry(),void createEntry(),这两方法,从而实现它的双链表结构。
public V put(K key, V value) {
//先判断当前的Entry[] 数组是否为空数组
if (table == EMPTY_TABLE) {
inflateTable(threshold); //如果为空,对表进行初始化
}
//判断key键是否为空
if (key == null)
return putForNullKey(value); //在HashMap中允许value值为空
int hash = hash(key); //计算key的hash值
int i = indexFor(hash, table.length); //通过哈希值和当前的数据长度,计算出在数组的存放位置
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
//如果计算的hash值位置有值,并且key值相同,覆盖原来的value,将原值返回
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i); //存放值的具体实现,LinkedHashMap重写了其方法
return null;
}
//重写
void addEntry(int hash, K key, V value, int bucketIndex) {
super.addEntry(hash, key, value, bucketIndex);//先调用父类的方法
//删除最近最少使用元素的策略定义
// Remove eldest entry if instructed
Entry<K,V> eldest = header.after;
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
}
}
//调用的父类的addEntry()方法
void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
createEntry(hash, key, value, bucketIndex);//将新元素以双向链表的形式加入
}
//重写
void createEntry(int hash, K key, V value, int bucketIndex) {
HashMap.Entry<K,V> old = table[bucketIndex];
Entry<K,V> e = new Entry<>(hash, key, value, old);
table[bucketIndex] = e;
e.addBefore(header); // 调用元素的addBrefore方法,将元素加入到哈希、双向链接列表。
size++;
}
以上部分源码基于JDK1.7。
来源:https://www.cnblogs.com/128-cdy/p/12298606.html