Java集合源码剖析——基于JDK1.8中HashSet、LinkedHashSet的实现原理

简介: Java集合源码剖析——基于JDK1.8中HashSet、LinkedHashSet的实现原理

文章目录:


1.开篇

2.HashSet中的属性

3.HashSet中的方法

3.1 构造方法一

3.2 构造方法二

3.3 构造方法三

3.4 构造方法四

3.5 构造方法五

3.6 迭代器Iterator方法

3.7 size方法

3.8 isEmpty方法

3.9 contains方法

3.10 add方法

3.11 remove方法

3.12 clear方法

4.LinkedHashSet中的方法



1.开篇


前面三篇文章分别说到了 List 接口中的常用几个实现类:ArrayListLinkedListVector


Java集合体系中,List继承了Collection接口,Collection接口又继承了Iterable接口,而在Collection接口的主要的子接口中还有一个兄弟:Set


这篇文章主要来讲讲Set接口的主要实现类 HashSetLinkedHashSet的实现原理。那么我们看过部分源码的都知道Set集合的底层实际上就是相应的Map,所以说Set还不如说Map呢,所以这篇文章就简单的对Set集合的源码进行一个分析吧。

2.HashSet中的属性


·       HashSet的底层其实就是HashMap(哈希表数据结构),new HashSet的时候实际上就是new了一个HashMap

·       HashSet集合元素的特点:无序、不可重复、没有下标。

·       HashSet集合的默认初始化容量是16,默认加载因子是 .75。(HashMap

//底层使用 HashMap 来保存 HashSet 中所有元素
private transient HashMap<E,Object> map;
//定义一个虚拟的 Object 对象作为 HashMap 的 value,将此对象定义为 static final
private static final Object PRESENT = new Object();

3.HashSet中的方法


3.1 构造方法

//默认的无参构造器,构造一个空的 HashSet
//实际底层会初始化一个空的 HashMap,并使用默认初始容量为 16 和加载因子 0.75
public HashSet() {
    map = new HashMap<>();
}


3.2 构造方法二

//构造一个包含指定 collection 中的元素的新 set
//实际底层使用默认的加载因子 0.75 和足以包含指定 collection 中所有元素的初始容量来创建一个 HashMap
//c 其中的元素将存放在此 set 中的 collection
public HashSet(Collection<? extends E> c) {
    map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
    addAll(c);
}


3.3 构造方法三

//以指定的 initialCapacity 和 loadFactor 构造一个空的 HashSet
//实际底层以相应的参数构造一个空的 HashMap
//initialCapacity 初始容量,loadFactor 加载因子
public HashSet(int initialCapacity, float loadFactor) {
    map = new HashMap<>(initialCapacity, loadFactor);
}


3.4 构造方法四

//以指定的 initialCapacity 构造一个空的 HashSet
//实际底层以相应的参数及加载因子 loadFactor 为 0.75 构造一个空的 HashMap
public HashSet(int initialCapacity) {
    map = new HashMap<>(initialCapacity);
}


3.5 构造方法五

//以指定的 initialCapacity 和 loadFactor 构造一个新的空链接哈希集合
//此构造函数为包访问权限,不对外公开,实际只是是对 LinkedHashSet 的支持
//实际底层会以指定的参数构造一个空 LinkedHashMap 实例来实现
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}


3.6 迭代器Iterator方法

//返回对此 set 中元素进行迭代的迭代器。返回元素的顺序并不是特定的。
//底层实际调用底层 HashMap 的 keySet 来返回所有的 key
//可见 HashSet 中的元素,只是存放在了底层 HashMap 的 key 上,
//value 使用一个 static final 的 Object 对象标识
public Iterator<E> iterator() {
    return map.keySet().iterator();
}


3.7 size方法

//返回此 set 中的元素的数量(set 的容量)
//底层实际调用 HashMap 的 size()方法返回 Entry 的数量,就得到该 Set 中元素的个数
public int size() {
    return map.size();
}


3.8 isEmpty方法

//如果此 set 不包含任何元素,则返回 true
//底层实际调用 HashMap 的 isEmpty()判断该 HashSet 是否为空
public boolean isEmpty() {
    return map.isEmpty();
}


3.9 contains方法

//如果此 set 包含指定元素,则返回 true
//更确切地讲,当且仅当此 set 包含一个满足(o==null ? e==null : o.equals(e))的 e 元素时,返回 true
//底层实际调用 HashMap 的 containsKey 判断是否包含指定 key
public boolean contains(Object o) {
    return map.containsKey(o);
}


3.10 add方法

//如果此 set 中尚未包含指定元素,则添加指定元素
//更确切地讲,如果此 set 没有包含满足(e==null ? e2==null : e.equals(e2))的元素 e2,则向此 set 添加指定的元素 e
//如果此 set 已包含该元素,则该调用不更改 set 并返回 false
//底层实际将将该元素作为 key 放入 HashMap。
//由于 HashMap 的 put()方法添加 key-value 对时,当新放入 HashMap 的 Entry 中 key 与集合中原有 Entry 的 key 相同(hashCode()返回值相等,通过 equals 比较也返回 true)
//新添加的 Entry 的 value 会将覆盖原来 Entry 的 value,但 key 不会有任何改变,
//因此如果向 HashSet 中添加一个已经存在的元素时,新添加的集合元素将不会被放入 HashMap 中,原来的元素也不会有任何改变,这也就满足了 Set 中元素不重复的特性
public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}


3.11 remove方法

//如果指定元素存在于此 set 中,则将其移除
//更确切地讲,如果此 set 包含一个满足(o==null ? e==null : o.equals(e))的元素e,则将其移除。如果此 set 已包含该元素,则返回 true
//(或者:如果此 set 因调用而发生更改,则返回 true)。(一旦调用返回,则此 set 不再包含该元素)。
//底层实际调用 HashMap 的 remove 方法删除指定 Entry
public boolean remove(Object o) {
    return map.remove(o)==PRESENT;
}


3.12 clear方法

//从此 set 中移除所有元素。此调用返回后,该 set 将为空
//底层实际调用 HashMap 的 clear 方法清空 Entry 中所有元素
public void clear() {
    map.clear();
}


4.LinkedHashSet中的方法


LinkedHashSet 是 HashSet 的一个子类。LinkedHashSet 是具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。此实现与HashSet 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可为插入顺序或是访问顺序。


注意,此实现不是同步的。如果多个线程同时访问链接的哈希 Set,而其中至少一个线程修改了该 Set,则它必须保持外部同步。


对于 LinkedHashSet 而言,它继承与 HashSet、又基于 LinkedHashMap 来实现的。LinkedHashSet 底层使用 LinkedHashMap 来保存所有元素,它继承与 HashSet,其所有的方法操作上又与 HashSet 相同,因此 LinkedHashSet 的实现上非常简单,只提供了四个构造方法,并通过传递一个标识参数dummy,调用父类的构造器,底层构造一个 LinkedHashMap来实现,在相关操作上与父类 HashSet 的操作相同,直接调用父类 HashSet 的方法即可。


//构造一个带有指定初始容量和加载因子的新空链接哈希 set
//底层会调用父类的构造方法,构造一个有指定初始容量和加载因子的 LinkedHashMap 实例
initialCapacity 初始容量,loadFactor 加载因子
public LinkedHashSet(int initialCapacity, float loadFactor) {
    super(initialCapacity, loadFactor, true);
}
//构造一个带指定初始容量和默认加载因子 0.75 的新空链接哈希 set
//底层会调用父类的构造方法,构造一个带指定初始容量和默认加载因子 0.75 的 LinkedHashMap 实例
public LinkedHashSet(int initialCapacity) {
    super(initialCapacity, .75f, true);
}
//构造一个带默认初始容量 16 和加载因子 0.75 的新空链接哈希 set
//底层会调用父类的构造方法,构造一个带默认初始容量 16 和加载因子 0.75 的 LinkedHashMap 实例
public LinkedHashSet() {
    super(16, .75f, true);
}
//构造一个与指定 collection 中的元素相同的新链接哈希 set
//底层会调用父类的构造方法,构造一个足以包含指定 collection中所有元素的初始容量和加载因子为 0.75 的 LinkedHashMap 实例
//c 其中的元素将存放在此 set 中的 collection
public LinkedHashSet(Collection<? extends E> c) {
    super(Math.max(2*c.size(), 11), .75f, true);
    addAll(c);
}


相关文章
|
7月前
|
存储 小程序 Java
热门小程序源码合集:微信抖音小程序源码支持PHP/Java/uni-app完整项目实践指南
小程序已成为企业获客与开发者创业的重要载体。本文详解PHP、Java、uni-app三大技术栈在电商、工具、服务类小程序中的源码应用,提供从开发到部署的全流程指南,并分享选型避坑与商业化落地策略,助力开发者高效构建稳定可扩展项目。
|
10月前
|
存储 安全 Java
Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
452 3
|
11月前
|
JavaScript Java 关系型数据库
家政系统源码,java版本
这是一款基于SpringBoot后端框架、MySQL数据库及Uniapp移动端开发的家政预约上门服务系统。
345 6
家政系统源码,java版本
|
11月前
|
供应链 JavaScript 前端开发
Java基于SaaS模式多租户ERP系统源码
ERP,全称 Enterprise Resource Planning 即企业资源计划。是一种集成化的管理软件系统,它通过信息技术手段,将企业的各个业务流程和资源管理进行整合,以提高企业的运营效率和管理水平,它是一种先进的企业管理理念和信息化管理系统。 适用于小微企业的 SaaS模式多租户ERP管理系统, 采用最新的技术栈开发, 让企业简单上云。专注于小微企业的应用需求,如企业基本的进销存、询价,报价, 采购、销售、MRP生产制造、品质管理、仓库库存管理、财务应收付款, OA办公单据、CRM等。
690 23
|
12月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
701 7
|
Java
java8中LinkedHashSet是如何实现的
LinkedHashSet是Set集合的一个实现,具有set集合不重复的特点,同时具有可预测的迭代顺序,也就是我们插入的顺序。 那么LinkedHashSet和LinkedHashMap有什么区别?它又是如何实现链表的?今天我们就从java8版本来看看LinkedHashSet是如何实现的。
307 0
|
6月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
295 1
|
6月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
317 1
|
7月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
288 0