搞懂 HashSet & LinkedHashSet 源码 以及集合常见面试题目
经过上两篇的 HashMap 和 LinkedHashMap 源码分析以后,本文将继续分析 JDK 集合之 Set 源码,由于有了之前的 Map 源码分析的铺垫,Set 源码就简单很多了,本文的篇幅也将比之前短很多。查看 Set 源码的构造参数就可以知道,Set 内部其实维护的就是一个 Map,只是单单使用了 Entry 中的 key 。那么本文将不再赘述内部数据结构,而是通过部分的源码,来说明两个 Set 集合与 Map 之间的关系。本文将从以下几部分叙述:
- Set 集合概述
- HashSet 源码简单分析
- LinkedHashSet 源码简单分析
- 关于面试中的集合问题总结
Set 集合概述
图片来自互联网侵删
由于本篇文章主要叙述 Set 容器以及和 Map 容器之间关系,我们只需要关注上述集合图谱中 Set 部分。可以看出 Set 主要的实现类有 HashSet
和 TreeSet
以及没有画出的 LinkedHashSet
。其中 HashSet
的实现依赖于 HashMap
, TreeSet
的实现依赖于 TreeMap
,LinkedHashSet
的实现依赖于 LinkedHashMap
。
从各个实现类的声明也可以看出其继承关系
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
在看 Set 的之前,我们先概括的说下 Set 集合的特点
- HashSet 底层是数组 + 单链表 + 红黑树的数据结构
- LinkedHashSet 底层是 数组 + 单链表 + 红黑树 + 双向链表的数据结构
- Set 不允许存储重复元素,允许存储 null
- HashSet 存储元素是无序且不等于访问顺序
- LinkedHashSet 存储元素是无序的,但是由于双向链表的存在,迭代时获取元素的顺序等于元素的添加顺序,注意这里不是访问顺序
HashSet 的源码分析
HashSet 源码只有短短的 300 行,上文也阐述了实现依赖于 HashMap,这一点充分体现在其构造方法和成员变量上。我们来看下 HashSet 的构造方法和成员变量:
// HashSet 真实的存储元素结构