栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Collection集合工具类源码解读(四) --- HashTable,HashSet,LinkedHashMap,LinkedHashSet

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Collection集合工具类源码解读(四) --- HashTable,HashSet,LinkedHashMap,LinkedHashSet

文章目录

5、HashTable

5.1 先看看属性5.2 构造函数5.3 从put方法分析扩容机制

put方法addEntry方法(真正添加值的方法)rehash方法(扩容)扩容总结: 5.4 get方法5.5 remove方法5.6 replace5.7 HashTable和HashMap 6、HashSet

6.1 先看看属性6.2 构造方法6.3 add方法6.4 remove方法6.5 contains 7、linkedHashMap

7.1 先看看属性7.2 构造方法7.3 linkedHashMap完善的方法

1.afterNodeAccess方法2.afterNodeRemoval方法3.afterNodeInsertion方法 7.4 get方法 8、linkedHashSet
往期:

Collection集合工具类源码解读(一) — ArrayList 和 VectorCollection集合工具类源码解读(二) — linkedListCollection集合工具类源码解读(三) — HashMap 5、HashTable

先写个demo,debug

public static void main(String[] args) {
    Hashtable hashtable = new Hashtable<>();
    for (int i = 1; i <= 9; i++) {
        hashtable.put(i+"",i);
    }
    hashtable.put("bbb",10);
    hashtable.put(null,11);

    hashtable.put("ccc",null);

}
5.1 先看看属性

Hashtable和HashMap类似,他俩都实现了Map接口,但是hashtable继承自Dictionary,hashmap继承自AbstractMap

严格意义上来说应该是hashmap像hashtable,因为hashtable是jdk1.0出现的,hashmap是1.2出现的,hashmap是轻量级的hashtable

table:哈希表count:哈希表长度,容量threshold:扩容门槛loadFactor:加载因子 5.2 构造函数

四个构造函数:

Hashtable():无参构造,默认初始容量为11,加载因子为0.75,初始门槛为0.75*11=8(初始容量与hashmap不同)Hashtable(int initialCapacity):自定义容量,加载因子还是0.75Hashtable(int initialCapacity, float loadFactor):自定义容量,加载因子。扩容门槛为容量*加载因子Hashtable(Map t):传入一个map,根据map大小初始化,加载因子仍然是0.75

如果map的size比11大则初始化map两倍的容量否则就是初始化11的长度 5.3 从put方法分析扩容机制 put方法

进入put方法

    首先判断value(实际上key也不能为null,在hashcode方法里如果key为null,就会空指针)是否为空,为空就抛出空指针异常(所以hashtable键和值都不能为空)然后拿到原来的table,用hash计算下标,用index计算下标,这里和0x7FFFFFFF(32位整数最大位)相与就是限定位数的,超过部分与0就是0。最后用table[index]拿到当前索引位置先看看当前table[i]有不有值,有就遍历找key相等的,然后替换这个值table[i]为空,就直接addEntry进去
addEntry方法(真正添加值的方法)

如图:addEntry方法

    判断之前的count是否到达扩容门槛,到达了就rehash扩容
      hash计算最新的index
    把值丢进table里count++
rehash方法(扩容)

如图为rehash方法

    拿到旧容量和旧table计算新容量:左移一位再加一:old * 2 +1 ,然后再判断是否超过范围计算新门槛:新容量*加载因子 ,然后再判断是否超过范围把旧元素移到新的table里

扩容总结:

hashtable 默认容量为11,默认加载因子为0.75,所以第一次扩容门槛为11*0.75=8扩容时:在添加当前要添加的数之前执行。判断之前的count是否大于等于当前的容量

如果大于等于就要扩容 扩容机制:newCapacity = oldCapacity * 2 + 1 5.4 get方法

首先注意到get方法加了synchronized,实际上,hashtable所有方法都加了synchronized

实际上方法里面的思想和hashmap是一样的

get方法传递一个key,返回查到的值,如果查不到返回nullgetOrDefault,传递一个key,defaultValue,查到返回查到的值,查不到返回默认值 5.5 remove方法

同样的加了synchronized,思想是先计算hash对应的table[i],再在这条链表上遍历找到要删除的,按照链表的方式删除

5.6 replace

可以看到,先判空,然后找到原来的值,更换新的值,和hashmap是大相径庭的

5.7 HashTable和HashMap

HashMap不是线程安全的,HashTable由于方法加了synchronized是线程安全,效率上可能hashmap高(差别在锁的消耗)

Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差 HashMap允许null key和null value,而hashtable不允许null key和null valueHashMap继承AbstractMap类,Hashtable继承自Dictionary类初始容量不同:hashmap初始为16,hashtable初始为11 6、HashSet

先写个demo,debug

public class HashSetDemo {
    public static void main(String[] args) {
        HashSet set = new HashSet<>();
        set.add("java");
        set.add("java");

    }
}
 
6.1 先看看属性 

HashSet里面内嵌一个HashMap,还有个常量PRESENT为空对象

HashSet添加的元素作为hashMap的key,这个PRESENT空对象作为hashmap的value

6.2 构造方法

hashSet构造方法完全使用的是hashMap,没什么可说的

6.3 add方法

HashSet就是调用的hashmap的put方法

将添加的元素作为hashMap的key,PRESENT空对象作为hashmap的value

所以为什么set能排重,就是这个原因:

hashmap用key计算hash,每次key相同就替换调原来的值所以用set插入相同的两个元素,两个元素在hashmap里面都是key:PRESENT无论怎么替换key只有一个,所以能够排重 6.4 remove方法

又是调用的hashmap的remove方法,hashmap的remove传入一个Object,如果找到了就返回这个Object并删除,如果不存在就返回null

6.5 contains

hashSet的contains方法是对hashmap的containsKey的封装

7、linkedHashMap 7.1 先看看属性

linkedHashMap是继承自HashMap的,他对HashMap的Entry进行了修改,多了一个before和after用来互相连接,同时这个Entry有head和tail头和尾

简单来说:linkedHashMap维护了一个双向链表

注意注意注意:这个类由于是继承HashMap,所有方法基本上都是稍微重写了一下HashMap的

还有一点:accessOrder属性:

false(默认),基于插入顺序:顺序是插入是固定的true:基于访问顺序:每次访问会调用afterNodeAccess方法将其移到末尾 7.2 构造方法

就是调用HashMap的构造方法,没什么好说的

7.3 linkedHashMap完善的方法

在HashMap里面,留了三个空方法,就是给linkedHashMap使用的

1.afterNodeAccess方法

当结点加入HashMap后一并加入linkedHashMap里面的双向链表后

2.afterNodeRemoval方法

当删除结点时也从双向链表中移除

3.afterNodeInsertion方法

如果传入的值为true,就删除链表头结点

7.4 get方法

这个get方法,linkedHashMap对其进行了重写,主要是对accessOrder = true的情况。基于访问顺序,每次查看都会把查看过的结点放到末尾

8、linkedHashSet

linkedHashSet代码一共就200行

关键代码是调用了HashSet里面那个default修饰的构造函数

实际上底层仍然是linkedHashMap,所以就不过多赘述了

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号