Set 表示由无重复对象组成的集合,也是集合框架中重要的一种集合类型,直接扩展自 Collection 接口。在一个 Set 中,不能有两个引用指向同一个对象,或两个指向 null 的引用。若是对象 a 和 b 的引用知足条件 a.equals(b),那么这两个对象也不能同时出如今集合中。java
一般 Set 是不要求元素有序的,但也有一些有序的实现,如 SortedMap 接口、LinkedHashSet 接口等。安全
Set 的具体实现一般都是基于 Map 的。由于 Map 中键是惟一的,于是在基于 Map 实现 Set 时,只须要关心 Map 中的键,和键关联的值不须要有意义,使用一个任意的对象“占位”便可。咱们在前面分析 Map 中的迭代器时,KeySet() 方法获得的就是一个 Set。多线程
前面咱们分析过 Map 接口的几个具体实现,通用的实现 HahsMap
,插入或访问序的 LinkedHashMap
, 按照键升序的 TreeMap
。一样,在 Set 的具体实现中,也有 HashSet
、 LinkedHashSet
和 TreeSet
等,分别和 Map 一一对应,它们的特性对应着相应的 Map 实现的特性。下面基于 HashSet 的实现作一个简略的介绍。框架
1 |
|
从成员变量和构造方法能够清楚地看到,内部使用了一个 HahsMap,同时定义了一个无心义的空的静态 Object 对象(占用8byte) PRESENT。既然 map 中和键关联的值没有意义,为何不干脆使用 null 呢?咱们看一下 add() 方法:性能
1 |
public boolean add(E e) { |
Map 的 put() 方法在添加一个新的键时会返回 null,在更新一个已经存在的键关联的值时会返回旧值。于是 Set 中的 add() 方法能够据此判断新加入的元素是否改变了集合,若是改变了就返回 true。于是 PRESENT 不可使用 null 。this
其它的方法这里简单地列一下,都是基于 map 实现的:spa
1 |
public boolean contains(Object o) { |
Set 的内部一般是基于 Map 来实现的,Map 中的 Key 构成了 Set,而 Value 所有使用一个无心义的 Object 。 Set 的特征与其内部的 Set 的特征是一致的。基于 HashMap 的 HashSet 是无序时的最佳通用实现,基于 LinkedHashMap 的 LinkedHashSet 保留插入或访问的顺序,基于 TreeMap 的 TreeSet 能够按照元素升序排列,要求元素实现 Comaprable 接口或自定义比较器。线程
HashSet , LinkedHashSet, TreeSet 都不是线程安全的,在多线程环境下使用时要注意同步问题。code
CopyOnWriteArraySet 是一个线程安全的实现,可是并非基于 Map 实现的,而是经过 CopyOnWriteArrayList 实现的。使用 addIfAbsent() 方法进行去重,性能比较通常。对象