JavaSE 集合 Vol.1 Collection 源码入门 (含截图分析)

1. 前言


· 下期传送门:JavaSE 集合 Vol.2 Map 源码入门 (含截图分析)

· 本文章是用于 个人学习过程中 整理知识点的帖子,主题为:JavaSE 集合 Vol.1 Collection 源码入门

· 本文章 只包含了各个 集合实现类 常用的方法源码分析,并不全面,旨在培养源码的阅读能力。

· 本文章出现的 遗漏、错误 欢迎点开这篇文章的各位指出。

· 本文章的知识大纲根据 韩顺平老师 JavaSE 教学视频 进行编写。

感谢韩顺平老师带来的优质教学和对教育作出的贡献


2. Collection 集合 框架体系图

在这里插入图片描述


3. Collection 集合

● 常用方法 ●

指令解释
add ( Object e )添加单个元素
addAll ( Collection c )添加多个元素
remove ( Object e )删除单个元素
removeAll ( Collection<?> c )删除多个元素
contains ( Object e )查找单个元素
cotainsAll ( Collection<?> e )查找多个元素
clear ( )清空集合元素
size ( )查看集合长度
isEmpty ( )判断集合是否为空

● List 接口

基本介绍:

· List 集合类的元素是 有序可重复 的,也就是说它的 添加和取出 顺序是一致的,并且支持索引。


基本方法:

指令解释
add ( Object e )插入单个元素
add ( int index , Object element )从 指定位置 中 插入单个元素
addAll ( Object element )插入多个元素
addAll ( int index , Collection c )从 指定位置 中 插入多个元素
indexOf ( Object o )返回 元素在集合中 首次出现 的 位置下标
lastIndexOf ( Object o )返回 元素在集合中 最后一次出现 的 位置下标
remove ( Object o )删除元素
set ( int index , Object element )修改 指定位置下标 的 元素
subList ( int fromIndex , int toIndex )返回 指定位置范围内 的 元素内容 ( 前闭后开 )

· ArrayList 实现类

无参构造
● ArrayList 的数据都存放在数组: transient Object [ ] elementData 之中

● transient 译为 短暂的 作用是:不希望该属性被序列化

● 无参构造时 对象将 elementData 初始化为一个空数组


● 有参构造 ●
在这里插入图片描述
● 有参构造时 对象直接定义 elementData 数组的大小


扩容机制
在这里插入图片描述


· LinkedList 实现类

● 无参构造 ●

在这里插入图片描述
● LinkedList 底层维护着一个双向链表

● 无参构造时,直接新建一个 LinkedList 对象


添加数据 [ 流程概述 ]

执行添加操作时 调用 add() 方法 【 添加元素默认从尾部添加 】

① 进入 add() 方法 进入 创建双向链表 的方法

② 进入 linkLast() 方法

     a. 如果 新添加的节点 为 双向链表的 第一个节点
          i. 则让头节点 和 尾节点 都指向 该节点

     b.如果 新添加的节点 不为 双向链表的 第一个节点
          i. 则让原尾节点的后一个节点 指向 该节点
         ii. 该节点的前一个节点 指向 原尾节点
        iii. 尾节点 指向 该节点

③ 完成 添加数据 操作

综上所述:下面将对 添加数据 进行源码分析

添加数据

在这里插入图片描述


删除数据 [ 流程概述 ]

执行 删除操作时 调用 remove() 方法 【 无参数代表删除头节点 】

① 进入 removeFirst() 方法 定义 头节点 的 指针F 进入 真正删除数据 的方法

② 进入 unlinkFirst() 方法
     a. 定义 头节点的后节点 的 指针N
     b. 通过 指针F 删除 头节点 的数据 和 后节点
     c. 如果 指针N 不为空 则设置 指针N 的 前节点 为空
     d. 返回 头节点 原来的数据 用于特殊需求

③ 完成 删除数据 操作


综上所述:下面将对 删除数据 进行源码分析

删除数据

在这里插入图片描述


· Vector 实现类

无参构造

在这里插入图片描述
● Vector 的数据都存放在数组: protected Object[] elementData 之中

● protected 译为 受保护的 作用是:线程安全

● 无参构造时,通过有参构造 将 elementData 初始化为 10 长度的数组


有参构造

在这里插入图片描述
● Vector 的数据都存放在数组: protected Object[] elementData 之中

● protected 译为 受保护的 作用是:线程安全

● 有参构造时,通过有参构造 将 elementData 初始化为 10 长度的数组


扩容机制 [ 流程概述 ]

① 确认是否要进行扩容

     a. 进入 enshurCapacityHelper 方法
         如果 所需最小容量 > 当前数组长度 则进入 真正的扩容 方法

     b. 进入 grow 方法
         oldCapacity 属性 [保存旧数组的长度]
         newCapacity 属性 [保存新数组的长度,如果容量增量 > 0 扩容为旧数组的2倍]
         如果 新容量 < 所需最小容量 则 新容量 = 所需最小容量
         如果 新容量 > 类最大容量 则 进入大数扩容
         最后使用 Arrays.CopyOf() 方法 进行数组扩容

② 对数组进行赋值


综上所述:下面将对 扩容机制 进行源码分析

扩容机制

在这里插入图片描述


● Set 接口

基本介绍:

· 每一个实现 Set 接口类 的对象所包含元素是无序不可重复的,而且不支持索引


· HashSet 实现类

无参构造
在这里插入图片描述
● HashSet 的底层本质上是 HashMap

● 创建 HashSet 对象 也就是 创建 HashMap 对象


● 添加元素 [ 流程概述 ]

① 使用 HashSet 添加元素时,对象会先得到元素的 hash 值 并将其转成索引值

② 找到存储数据表 Table 查看这个索引位置是否已经存放元素

      a.如果没有 则直接加入

      b.如果有 则调用 equals 比较【equals 可以通过重写修改判断条件】

             i.如果添加的元素重复 则放弃添加

             ii.如果不重复 则添加元素到索引值对应链表的最后一位

根据 添加情况的不同分为:首次添加元素 、元素查重   两种添加情况

元素查重 是指:当 待添加的节点 分配到 不为空的链表中 进行处理的行为

元素查重 分为:添加不重复元素、添加重复元素   两种情况


综上所述:下面将对于 首次添加元素 、添加不重复元素 、 添加重复元素  三种情况  进行源码分析

首次添加元素

在这里插入图片描述

添加不重复元素

在这里插入图片描述

添加重复元素

在这里插入图片描述

扩容机制 [ 流程概述 ]

① 首次添加数据时,将 Table 数组容量 设置为 默认初始容量 16 ,数组阈值 12

② 如果发生以下两种情况的任意一种:

     A.Table 数组长度 超过当前 数组阈值

     B.Table 数组 中某一条链表的 结点个数 超过当前 链表阈值

     Table 数组容量 就会扩容到 16 × 2 = 32 ,数组阈值 也会随之更新:32 × 0.75 = 24   以此类推

名词解释:

Table 数组当前 HashSet 对象的 哈希表

数组阈值Table 数组容量 × 加载因子

数组阈值threshold 】【 Table 数组长度size

加载因子LOADFACTOR  默认值 0.75 】

默认初始容量DEFAULT_INITIAL_CAPACITY  默认值 16 】

链表阈值TREEIFY_THRESHOLD   默认值 8 】


综上所述:下面将根据如上 三种情况 分别对 扩容机制 进行不同角度的源码分析

扩容机制 [ ① 首次添加数据 ]

在这里插入图片描述

扩容机制 [ ② 扩容哈希表 的 A 情况 ]

在这里插入图片描述

扩容机制 [ ② 扩容哈希表 的 B 情况 ]

在这里插入图片描述


树化链表 [ 流程概述 ]

在 Java 8 中,如果以下两个条件同时发生:

     1. Table数组 中的一条链表的 结点个数 超过 链表阈值

     2. Table 数组长度 不小于 最小树容量

     就会对该链表进行树化操作,将其变成 红黑树


名词解释:

Table 数组当前 HashSet 对象的 哈希表

Table 数组长度size

链表阈值TREEIFY_THRESHOLD   默认值 8 】

最小树容量MIN_TREEIFY_CAPACITY  默认值 64 】

红黑树:平衡二叉树的子分支,一种用于存储操作数据的高效数据结构 】


综上所述:下面将对 树化链表 进行源码分析

树化链表

在这里插入图片描述


· LinkedHashSet 实现类


基本介绍

LinkedHashSetHashSet 的子类。它的底层是 LinkedHashMap。其结构是:数组+双向链表

LinkeHashSet 遍历元素 和 插入元素 的 顺序一致,但它 不允许元素重复

底层结构

LinkedHashSet 底层维护的是 LinkedHashMap 【HashMap的子类】

首次添加元素时,直接将 Table数组 扩容到 16 ,将添加的元素打包成一个结点

结点 包含两个属性:pre 前结点、 after 后结点

Table数组的类型HashMap$Node[]】 【存放结点的类型LinkedHashMap$Entry

这里体现出了多态性质: 子类的对象可以存放至父类的对象数组中


无参构造

在这里插入图片描述


添加元素 [ 流程概述 ]

在添加一个元素时,先求出它的 hash 值,再求出索引位置,确定该元素要放在 Table 数组的 哪一个

位置,然后将添加的元素加入到双向链表中,如果元素重复,则不添加。

添加元素 分为 首次添加元素、元素查重 两种情况


综上所述:下面将对 首次添加元素、元素查重 两种情况 进行源码分析

首次添加元素

在这里插入图片描述


元素查重 分为 元素不重复、元素重复 两种情况

元素查重 [ 元素不重复 ]

在这里插入图片描述

元素查重 [ 元素重复 ]

在这里插入图片描述


· TreeSet 实现类


基本介绍

· TreeSet 与 HashSet 是 并类关系 。它的底层是 TreeMap 。其结构是:二叉树

· TreeSet 遍历元素 和 插入元素 的 顺序不一致,而且 不允许元素重复

底层结构

· TreeSet 底层维护的是 TreeMap


基本特点

· 与 HashSet 不同,TreeSet 中提供了一个 特殊的有参构造方法

· 这个有参构造方法传入的参数是 Comparator 接口对象 。

· Comparator 接口,又称作 比较器,该接口可以自定义 用于数据之间排序的规则


综上所述:下面将演示 有参构造中自定义排序 的 过程。

无参构造下遍历 TreeSet

在这里插入图片描述
在这里插入图片描述

有参构造自定义排序

在这里插入图片描述
在这里插入图片描述


· 从 有参构造 自定义排序 中可以看到,我们实现了 Comparator 接口 的 compare 方法

· 通过 compare 方法,我们将 当前 TreeSet 对象 存储的数据进行 自定义排序规则

· 这里演示的是使用 String 类compareTo 方法 ,比较两个字符串 首字母 ASCII码值 的大小 。


【详细的源码分析,放在 下一章节:Map 源码入门 中讲解】


● Queue 接口

基本介绍:

·


· LinkedList 实现类


· PriorityQueue 实现类


· 下期传送门:JavaSE 集合 Vol.2 Map 源码入门 (含截图分析)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值