Java 集合篇之 set,面试官:请说一说 HashSet、LinkedHashSet、TreeSet 的区别?
写在开头
Java 的集合世界中主要由 List,Set,Queue,Map 构成,我们在之前的博文中已经学习了 List,接下来我们继续学习 Set 集合。Set 特点:存取无序,不可以存放重复的元素,不可以用下标对元素进行操作
HashSet
作为 Set 容器的代表子类,HashSet 经常被用到,我们通过源码去分析它
【源码查看】
虽然 HashSet 实现了 Set 接口,但通过源码我们能够看到,它的底层逻辑实现其实依据的是 HashMap,通过操作 map 的 key 值来实现元素的增删改查,下面通过一个小测试类去用下 HashSet。
【代码示例 1】
输出:
由代码结果进一步证明了我们的结论:1、存储数据不重复,但 add 重复数据并不报错,原因是第一个数据会被第二次重复数据覆盖掉;2,无序,很多人发现输出了一个有序的数字集合,这个其实与我们所说的有序是有区别的,在 Set 中的有序无序是指输入的顺序与输出的顺序是否一致 当然,想要实现有序可以通过 LinkedHashSet,底层通过链表记录元素插入顺序。
面试考点
这里面其实包含着一个小小的 Java 面试考点,曾经有面试官问过这样的一个问题:
集合中的无序性和不可能重复性的什么意思?
无序性:所谓无序性不等于随机性,也不等于输出无序,就如同上面我们看到的向 HashSet 中随机添加数字,输出是从大到小,看似有序,实际此序非彼序!真正的无序性是指存储的数据在底层数组中并非按照数组索引的顺序添加 ,而是根据数据的哈希值进行判断。
不可重复性:指添加的元素按照 equals() 判断时 ,返回 false,因此,实现不可重复性,必须要同时重写 equals() 方法和 hashCode() 方法。
LinkedHashSet
那么有的小伙伴会问了:“我就想存一个不重复的数据集合,同时又想要他们有序怎么办呢?”,Java 的开发人员已经早就为你想到了,这个办法就是用 LinkedHashSet!LinkedHashSet 是基于 LinkedHashMap 实现的,并且使用链表维护了元素的插入顺序,具有快速查找、插入和删除操作的优点,又可以维护元素的插入顺序!源码就不带大家看了,咱们直接上测试案例。
【代码示例 2】
输出:
通过输出结果我们可以得出结论:LinkedHashSet 中的元素不可重复,有序。
TreeSet
通过上面两个集合类我们大概能够猜到,几乎所有的 Set 集合的底层都是通过 Map 去实现,TreeSet 同样是基于 TreeMap 实现,TreeMap 基于红黑树实现,所以 TreeSet 也就自带了排序功能。
【代码示例 3】
输出:
总结
HashSet、LinkedHashSet 和 TreeSet 都是 Set 接口的实现类,都能保证元素唯一,并且都不是线程安全的。
HashSet、LinkedHashSet 和 TreeSet 的主要区别在于底层数据结构不同。HashSet 的底层数据结构是哈希表(基于 HashMap 实现)。LinkedHashSet 的底层数据结构是链表和哈希表,元素的插入和取出顺序满足 FIFO。TreeSet 底层数据结构是红黑树,元素是有序的,排序的方式有自然排序和定制排序。
底层数据结构不同又导致这三者的应用场景不同。HashSet 用于不需要保证元素插入和取出顺序的场景,LinkedHashSet 用于保证元素的插入和取出顺序满足 FIFO 的场景,TreeSet 用于支持对元素自定义排序规则的场景。
此外,HashSet、LinkedHashSet 允许有 null 值,TreeSet 不允许有 null 值,当向 TreeSet 插入 null 元素时,TreeSet 使用 compareTo 方法与 null 元素进行比较,报错:java.lang.NullPointerException。
文章转载自:JavaBuild
评论