Java进阶08 集合(续)&Stream流
一、HashSet集合类(续)
1、JDK7(-)HashSet原理解析
1.1 底层结构
数组+链表
1.2 执行过程
①创建一个默认长度为16的数组,数组名为table
②根据元素的哈希值跟数组的长度求余计算出应存入的位置
③判断当前位置是否为null,如果是null直接头插法存入
④如果位置不为null,表示该位置已用元素,则调用equals方法比较
⑤如果元素内容一样,则不存;如果不一样,则头插法存入
2、JDK8(+)HashSet原理解析
2.1 底层结构
哈希表(数组+链表+红黑树)
2.1 执行过程
①创建HashSet集合,默认长度为16、默认加载因子0.75的数组,数组名table
②调用集合的添加方法,添加对象调HashCode方法计算出应存入的索引位置(二次哈希值%数组长度)
③判断索引位置元素是否是null:是null,尾插法存入、不是null说明有元素,调用equals方法比较内容
④比较内容一样,不存;不一样,尾插法存入
2.3 提高查询性能
-
扩容数组
扩容条件
-
当数组中的元素个数到达了16*0.75(加载因子)=12,扩容发生在第13次,扩容原数组2倍的大小,
-
链表挂载的元素超过了8(阈值),并且数组长度没有超过64
-
-
链表转红黑树(极少触发)
链表挂载的元素超过了(>)阈值8个,并且数组长度到达了(>=)64
3、相关面试题
Q:请说明HashSet实现的原理
A:首先,在添加元素时会先调用HashCode方法得到一个应存入位置的索引,然后检查该位置上是否有元素,没有直接尾插法存入,已有元素就需要调用equals方法逐个与该索引位置已存入的元素比较内容;内容均不相同则尾插法存入,相同就不存。其次,HashCode计算索引位置的过程是:首先调用HashCode方法得到原始的哈希值,再对该值进行哈希扰动右移16位,再和原始哈希值做异或操作得到二次哈希值,最后使用二次哈希值模与数组长度得到索引位置。但是在源码实现中,最后索引计算是通过数组长度减1再和二次哈希值逻辑与得到的,结果和上面一致,但与的执行效率比模更快。最后,之所以要对哈希值进行这么多复杂的操作是为了尽可能让要添加的元素哈希值散列在不同索引下,降低索引冲突。
二、LinkedHashSet集合类
LinkedList是Set集合中唯一可以去重并且存取有序的集合
1、存取有序原理
底层数据结构依然是哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序
单列集合使用场景大总结
List派系集合中,ArrayList集合首选;Set集合中,HashSet集合用的最多!
-
集合元素可重复→→→选择ArrayList集合(用的最多)
-
集合元素可重复,且增删操作多于查询→→→选择LinkedList
-
对集合元素去重→→→选择HashSet集合(用的最多)
-
对集合元素去重,且保证存取顺序→→→选择LinkedHashSet,效率低于HashSet
-
对集合元素进行排序→→→选择TreeSet,后续也可以用List集合实现排序
三、Collections集合类
1、可变参数
JDK5版本出现的技术,可以在定义方法的时候灵活的接收参数(可以不给参数,可以给1个或多个,也可以给一个数组),其底层本质就是一个数组。
-
格式:数据类型…参数名称,参考addAll方法的第二个参数
-
注意事项:一个形参列表中可变参数只能有一个;可变参数必须放在形参列表的最后面。
2、Collections集合工具类
java.utils.Collections是集合工具类,并不属于集合,只是用来操作集合的工具类
2.1 常用方法
方法
说明
public static boolean addAll(Collection< super T>