Set是无序且元素不可重复的集合
首先介绍一下Set是怎样保证元素不会重复的。当向Set中插入数据时,会首先调用元素对象中的hashCode()
方法,如果集合中不存在相同hashCode,则插入该元素。如果已经存在具有相同hashCode的元素,则会调用equals()
方法进行比较,如果返回true,表示相同,不插入元素,否则插入元素。因此
HashSet
HashSet
实现了Set
接口,在HashSet
中元素的存放的顺序和添加时的顺序毫无关联。
HashSet
是基于HashMap
实现的。在源码中,我们可以看到该类中有一个map
字段,当向HashSet
中插入元素时,实际上是向一个HashMap
添加元素,插入的元素作为map的键,map的值为HashSet
中定一个一个特定值PRESENT
。
注意该类是非线程安全的,如果想获得线程安全的HashSet
可以使用如下方法:
Collections.synchronizedSet(new HashSet<String>());
你已经发现了,在Set
中没有get(int index)
,因为前面已经提到过了Set
是无序集合,不能索引,所以没有get
方法。
LinkedHashSet
LinkedHashSet
继承自HashSet
,但是LinkedHashSet
与HashSet
不同的是,LinkedHashSet
保持着元素的添加顺序,其在内部维护着一个双向链表,这个链表保存着元素的次序,正因为如此,LinkedHashSet
在做插入操作时的性能要稍低于HashSet
。但是迭代的性能要好于HashSet
,因为LinkedHashSet
的迭代不受容量的影响,而与集合的大小成正比。
该类是非线程安全的,如果想获得线程安全的LinkedHashSet
可以使用如下方法:
Collections.synchronizedSet(new LinkedHashSet<String>());
TreeSet
TreeSet
实现了SortedSet
接口,从而保证了添加的元素按照元素的自然顺序(递增或其他顺序)在集合中进行存储,所以对于自定义的类,需要实现Comparable
接口。或者根据传入的实现Comparator
接口的实例来对元素进行排序。
TreeSet
是基于TreeMap
实现的。
TreeSet
是非线程安全的类,如果想获得线程安全的TreeSet
可以使用如下方法:
Collections.synchronizedSet(new TreeSet<String>());
在TreeSet
类中有一些比较有意思的方法,在这里做一个简单的介绍
public Iterator<E> descendingIterator()//返回在此Set集合上降序(反序)进行迭代的迭代器
public E floor(E e)//返回小于等于指定元素的最大元素,如果不存在,则返回null
public E ceiling(E e)//返回大于等于指定元素的最小元素,如果不存在,则返回null
...
CopyOnWriteArraySet
该类线程安全的。因为透过代码我们可以看到,该类是基于CopyOnWriteArrayList
实现的,所以该类共享CopyOnWriteArrayList
的基本属性,对写操作加锁并即写时复制(Copy-On-Write,是用于程序设计中的一种优化策略),对多操作不加锁。线程安全等。
ConcurrentSkipListSet
该类同样实现了SortedSet
接口,所以和TreeSet
一样,添加的元素按照元素的自然顺序(递增或其他顺序)在集合中进行存储,或者根据传入的实现Comparator
接口的实例来对元素进行排序。
该类是基于ConcurrentSkipListMap
实现的,是线程安全的,并且其迭代器是弱一致的,不会抛出ConcurrentModificationException
异常,可以并发地对集合处理其他操作。
遍历操作
Set集合的遍历方式同List基本上是一样,但是不能使用ListIterator进行遍历,在这里就不做具体介绍了。