前言
前面我们对Java集合框架有了一个基本的认识, 这里我们从几大接口入手, 逐步讲解其实现类; 下面要讲解的是
Set
的实现类, 即常用的HashSet
,TreeSet
和LinkedHashSet
文章源码基于JDK8
Java
集合框架系列博客:
正文
一. 概述
需要注意的是, 本文要讲的Set
的几个实现类内部都是基于Map
实现的, 比如: HashSet
基于HashMap
, TreeSet
基于TreeMap
, LinkedHashSet
基于LinkedHashMap
, Set
的value
实际上就是Map
中的key
, 依赖于Map
键值的唯一性实现Set
中元素的不可重复; 所以在学习Set
部分的时候, 只需要了解对应Map
的特点和实现就可以了; 因此, 本文也不会详细讲解各Set
实现类的代码细节, 而只是对每个实现类的特点进行一个总结
二. HashSet
HashSet
内部是基于HashMap
实现的, 所以在讲解HashSet
之前, 需要先看一下HashMap
的实现, 可以参照Java集合框架之HashMap, 该篇文章中详细介绍了HashMap
的实现原理和特点, 推荐对HashMap
有了一个大致的了解之后再开始往下读 ~
总体而言, HashSet
的代码比较简单, 其实现Set
元素不重复性其实是利用HashMap
键值的唯一性; 当我们存放一个Value
的时候, 其实是将该Value
当做HashMap
中的键值的, 而实现的各种常规操作, 比如: add()
, remove()
, contains()
等, 其实都是间接调用了HashMap
中的相应操作
所以, 这里不会去细讲HashSet
代码, 了解HashMap
之后, 其实是很简单的
这里只是贴一下HashSet
的特点:
-
没有重复元素, 允许
null
-
不保证
Set
的遍历顺序, 不保证元素的存储数据(具体原因可以见上面博客对HashMap
的分析) -
对
add()
,remove()
,contains()
,size()
方法提供常量时间 -
非同步, 可以使用
Collections.synchronizedSet(new HashSet(...));
-
Iterator
遍历的时候, 多线程抛出异常ConcurrentModificationException
(遍历过程中修改数据, 但是可以使用Iterator
自己提供的remove()
方法, 该方法不会造成异常)(原因参见Java集合框架之List中分析)
三. TreeSet
简要总结特点如下:
-
基于
TreeMap
实现 -
TreeSet
是一个有序的集合类, 默认为自然顺序, 也可根据提供的Comparator
排序 -
add()
,remove()
和contains()
需要logN
时间(是因为TreeMap
是基于红黑树实现的) -
非同步, 可以使用
Collections.synchronizedSortedSet(new TreeSet(...));
-
Iterator
抛异常:ConcurrentModificationException
四. LinkedHashSet
LinkedHashSet
基于LinkedHashMap
, 建议参照LinkedHashMap
的源码分析: Java集合框架之LinkedHashMap
总结特点如下:
-
访问有序(
LinkedHashMap
特点), 按照元素插入顺序访问(注意, 虽然LinkedHashSet
基于LinkedHashMap
实现, 而前面的文章分析了LinkedHashMap
有两种访问顺序, 但是LinkedHashSet
在构造LinkedHashMap
的时候使用的默认访问顺序, 即插入顺序(accessOrder = false
), 所以LinkedHashSet
的访问顺序只有一种, 即元素的插入顺序, 而且需要注意的是, 重复插入元素时是不会改变访问顺序的) -
非同步: 可以使用
Collections.synchronizedSet(new LinkedHashSet(...));
-
对
add()
,contains()
和remove()
提供常量时间(具体可以参见Java集合框架之HashMap中对HashMap
的分析)