HashTable 是一个线程安全的Map,它所有的方法都被加上了 synchronized 关键字,也是因为这个关键字,它注定成为了时代的弃儿 。
HashTable 底层采用 数组+链表 存储键值对,由于被弃用,后人也没有对它进行任何改进
HashTable 默认长度为 11,负载因子为 0.75F,即元素个数达到数组长度的 75% 时,会进行一次扩容,每次扩容为原来数组长度的 2 倍
HashTable 所有的操作都是线程安全的 。
文章插图
Collection 集合体系详解
Collection 集合体系的顶层接口就是 Collection,它规定了该集合下的一系列行为约定 。
该集合下可以分为三大类集合:List,Set 和 Queue
Set 接口定义了该类集合不允许存储重复的元素,且任何操作时均需要通过哈希函数映射到集合内部定位元素,集合内部的元素默认是无序的 。
List 接口定义了该类集合允许存储重复的元素,且集合内部的元素按照元素插入的顺序有序排列,可以通过索引访问元素 。
Queue 接口定义了该类集合是以队列作为存储结构,所以集合内部的元素有序排列,仅可以操作头结点元素,无法访问队列中间的元素 。
上面三个接口是最普通,最抽象的实现,而在各个集合接口内部,还会有更加具体的表现,衍生出各种不同的额外功能,使开发者能够对比各个集合的优势,择优使用 。
文章插图
Set 接口Set接口继承了 Collection 接口,是一个不包括重复元素的集合,更确切地说,Set 中任意两个元素不会出现 o1.equals(o2),而且 Set 至多只能存储一个 值元素,Set 集合的组成部分可以用下面这张图概括:
文章插图
在 Set 集合体系中,我们需要着重关注两点:
- 存入可变元素时,必须非常小心,因为任意时候元素状态的改变都有可能使得 Set 内部出现两个相等的元素,即 o1.equals(o2) = true,所以一般不要更改存入 Set 中的元素,否则将会破坏了 equals 的作用!
- Set 的最大作用就是判重,在项目中最大的作用也是判重!
AbstractSet 抽象类AbstractSet 是一个实现 Set 的一个抽象类,定义在这里可以将所有具体 Set 集合的相同行为在这里实现,避免子类包含大量的重复代码
所有的 Set 也应该要有相同的 hashCode 和 equals 方法,所以使用抽象类把该方法重写后,子类无需关心这两个方法 。
public abstract class AbstractSet<E> implements Set<E> {// 判断两个 set 是否相等public booleanequals(Object o) {if (o == this) { // 集合本身return true;} else if (!(o instanceof Set)) { // 集合不是 setreturn false;} else {// 比较两个集合的元素是否全部相同}}// 计算所有元素的 hashcode 总和public inthashCode {int h = 0;Iterator i = this.iterator;while(i.hasNext) {E obj = i.next;if (obj != ) {h += obj.hashCode;}}return h;}}
SortedSet 接口SortedSet 是一个接口,它在 Set 的基础上扩展了排序的行为,所以所有实现它的子类都会拥有排序功能 。
public interface SortedSet<E> extends Set<E> {// 元素的比较器,决定元素的排列顺序Comparator<? super E> comparator;// 获取 [var1, var2] 之间的 setSortedSet<E> subSet(E var1, E var2);// 获取以 var1 开头的 SetSortedSet<E> headSet(E var1);// 获取以 var1 结尾的 SetSortedSet<E> tailSet(E var1);// 获取首个元素E first;// 获取最后一个元素E last;}
HashSetHashSet 底层借助 HashMap 实现,我们可以观察它的多个构造方法,本质上都是 new 一个 HashMap
这也是这篇文章为什么先讲解 Map 再讲解 Set 的原因!先学习 Map,有助于理解 Set
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable {publicHashSet {this.map = new HashMap;}publicHashSet(int initialCapacity, float loadFactor) {this.map = new HashMap(initialCapacity, loadFactor);}publicHashSet(int initialCapacity) {this.map = new HashMap(initialCapacity);}}
我们可以观察 add 方法和 remove 方法是如何将 HashSet 的操作嫁接到HashMap 的 。
private static final Object PRESENT = new Object;public booleanadd(E e) {return this.map.put(e, PRESENT) == ;}public booleanremove(Object o) {return this.map.remove(o) == PRESENT;}
我们看到 PRESENT 就是一个静态常量:使用 PRESENT 作为 HashMap 的
推荐阅读
- 已有两种太空探测器飞出我们的太阳系 飞往太阳系外的探测器
- 生科医学|全国疫情形势呈逐渐企稳态势!上海两区首日达到社会面清零目标
- 两只耳朵配不一样的助听器,助听器需要两个耳朵都配吗??
- 前端开发和后端开发的区别?这两者哪个更累?
- 如何将两个pdf合并?合并pdf的快捷方法分享
- 验孕纸两条杠是怎么回事呢
- 喝白酒时,讲究这4个“最佳”,健康饮酒醉得慢,让你多喝二两半
- 减腰两边的赘肉怎么做?
- 水陆两栖动物名字大全 水陆两栖的动物是什么动物
- 花钱学Python?不存在的!一份大纲两个网站外加搜索,足矣