Set 接口实现的是 Collection接口,公开的方法和Collection的方法完全一致,没有提供特殊的方法,可见Set接口基本没有提供特殊的方法与实现,可见它是在通用的Collection里是提供抽象最为相似的一种集合。AbstractSet 实现了 Set接口,同时继承于 AbstractCollection , 关于AbstractCollection中的方法已经在《java数据结构与并发之--List(基础篇)》里已经做过了介绍,已经实现了Collection接口方法,而Set接口本身没有特殊的方法需要继承,在AbstractSet中只重写了 hashCode 和 equals 方法,另外根据Set本身的特征对removeAll方法进行重写来可能性的提高性能。同时值得注意的是,AbstractSet中并没有iterator()的方法进行实现,也没有扩展出特殊的iterator方法。
HashSet 和 LinkedHashSet 是我们经常会用到的常用的Set的实现类。我们先看一下HashSet,打开HashSet源码你会第一眼看到的就是 这样两个实例变量:
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
可以看出 HashSet 内部使用的数据结构全部是使用 HashMap 的实现去完成HashSet的基本功能的, 其中 PERSENT 是保留的一个对象用来填充 HashMap 的时候作为value,其中HashSet中的所有实现方法都依赖于HashMap,以及HashMap中的keySet(另外提一下在Map结构中也存在很多 Set的内部内实现于AbstractSet,这个在具体讲解到 Map 数据结构时再详细讲解),只有以下构造方法:
/**
* Constructs a new, empty linked hash set. (This package private
* constructor is only used by LinkedHashSet.) The backing
* HashMap instance is a LinkedHashMap with the specified initial
* capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hash map
* @param loadFactor the load factor of the hash map
* @param dummy ignored (distinguishes this
* constructor from other int, float constructor.)
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
}
此构造方法里使用到了LinkedHashMap, 此方法是包级别调用的,同时此方法为了在程序中多态被调用,居然是用了一个无效的参数,这样如果不看源码,还真不知道这居然是一个无用的参数,dummy无论传入true或者false都是同样的效果(这里并不值得学习)。
HashSet的内容就是这些,我们来看一下LinkedHashSet:(没有任何的特殊方法,只利用了我们上面说道的调用 LinkedHashMap 的特殊构造方法修改重写所有的HashSet构造方法,让所有的方法都走了 LinkedHashMap的实现。)
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
private static final long serialVersionUID = -2851667679971038690L;
/**
* Constructs a new, empty linked hash set with the specified initial
* capacity and load factor.
*
* @param initialCapacity the initial capacity of the linked hash set
* @param loadFactor the load factor of the linked hash set
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
/**
* Constructs a new, empty linked hash set with the specified initial
* capacity and the default load factor (0.75).
*
* @param initialCapacity the initial capacity of the LinkedHashSet
* @throws IllegalArgumentException if the initial capacity is less
* than zero
*/
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
/**
* Constructs a new, empty linked hash set with the default initial
* capacity (16) and load factor (0.75).
*/
public LinkedHashSet() {
super(16, .75f, true);
}
/**
* Constructs a new linked hash set with the same elements as the
* specified collection. The linked hash set is created with an initial
* capacity sufficient to hold the elements in the specified collection
* and the default load factor (0.75).
*
* @param c the collection whose elements are to be placed into
* this set
* @throws NullPointerException if the specified collection is null
*/
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
}
另外同样 Collections中提供了 EmptySet , SynchronizedSet 和 UnmodifiableSet,和 List中同理 EmptySet 是实现一个空的Set, 然后 SynchronizedSet 实现一个同步级的 Set,UnmodifiableSet针对修改的方法实现抛出异常来实现了不允许修改的含义。
前面的AbstractSet的子类提供的方法几乎没有对Collection接口进行特别的添加,同时java提供了另外一种Set接口: public interface SortedSet<E> extends Set<E>,我们可以看出这种接口继承至Set同时根据类名的意思就是可排序的Set接口,同时它新提供了以下接口方法:
Method Summary | |
---|---|
Comparator<? super E> | comparator() Returns the comparator used to order the elements in this set, or null if this set uses the natural orderingof its elements. |
E | first() Returns the first (lowest) element currently in this set. |
SortedSet<E> | headSet(E toElement) Returns a view of the portion of this set whose elements are strictly less than toElement. |
E | last() Returns the last (highest) element currently in this set. |
SortedSet<E> | subSet(E fromElement, E toElement) Returns a view of the portion of this set whose elements range from fromElement, inclusive, to toElement, exclusive. |
SortedSet<E> | tailSet(E fromElement) Returns a view of the portion of this set whose elements are greater than or equal to fromElement. |
提供了comparator方法,通过comparator内容进行返回相关的排序信息,同时提供了first,last 的获取方法,同时提供了 haedSet,tailSet, subSet 等截取方法,可以看出与List结构不同的是,它全部使用对象做为标记,而没有index概念。TreeSet 继承至SortedSet,java1.6又对SortedSet接口进行了扩展出了NavigableSet接口,TreeSet增加了NavigableSet接口的实现,其中NavigableSet接口多出了以下方法:
Method Summary | |
---|---|
E | ceiling(E e) Returns the least element in this set greater than or equal to the given element, or null if there is no such element. |
Iterator<E> | descendingIterator() Returns an iterator over the elements in this set, in descending order. |
NavigableSet<E> | descendingSet() Returns a reverse order view of the elements contained in this set. |
E | floor(E e) Returns the greatest element in this set less than or equal to the given element, or null if there is no such element. |
NavigableSet<E> | headSet(E toElement, boolean inclusive) Returns a view of the portion of this set whose elements are less than (or equal to, if inclusive is true)toElement . |
E | higher(E e) Returns the least element in this set strictly greater than the given element, or null if there is no such element. |
E | lower(E e) Returns the greatest element in this set strictly less than the given element, or null if there is no such element. |
E | pollFirst() Retrieves and removes the first (lowest) element, or returns null if this set is empty. |
E | pollLast() Retrieves and removes the last (highest) element, or returns null if this set is empty. |
NavigableSet<E> | subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) Returns a view of the portion of this set whose elements range from fromElement to toElement . |
SortedSet<E> | subSet(E fromElement, E toElement) Returns a view of the portion of this set whose elements range from fromElement, inclusive, to toElement, exclusive. |
NavigableSet<E> | tailSet(E fromElement, boolean inclusive) Returns a view of the portion of this set whose elements are greater than (or equal to, if inclusive is true) fromElement . |
接口中多出了更多的和顺序性相关的接口,包括倒序(descending*),临界的(ceiling,floor,higher,lower)最大值,最小值,另外提供了pollFirst, pollLast方法进行取出并删除首尾,同时对headSet,tailSet进行增强,这两个新方法提供了是否包含equals本元素。
CopyOnWriteArraySet 同样实现了 Set 接口的方法,没有特殊方法接口的开放特殊的方法接口,但是我们可以清晰看到 private final CopyOnWriteArrayList<E> al; 作为CopyOnWriteArraySet内部的数据结构,所有的方法都是通过调用 al 来实现的。具有Set特性的方法,通过CopyOnWriteArrayList提供的 addAllAbsent, addIfAbsent, remove等方法来实现其功能。可以看到CopyOnWriteArraySet 只是使用了 CopyOnWriteArrayList里的几个特有方法实现了Set的功能,其基本的内部原理都还和CopyOnWriteArrayList一样。
同样 ConcurrentSkipListSet 内不是也是使用的 ConcurrentNavigableMap ,然后构造方法中创建对应的ConcurrentSkipListMap,然后接口功能都是通过ConcurrentNavigableMap相应的方法实现。
从以上对Set的了解可以看出,Set接口的各种实现类基本都是通过内部对应的Map数据结构来实现,除了CopyOnWriteArraySet 使用了之前分析过的 CopyOnWriteArrayList做为内部数据结构进行实现的。分析Set的并发情况,其基本并发情况跟在说List中的情况基本一致,HashSet , LinkedHashSet, TreeSet 线程非安全,不适合多线程下被多个线程使用,多线程下的Set考虑使用 Collections.SynchronizedSet , CopyOnWriteArraySet ,其中CopyOnWriteArraySet 读操作频繁,写操作较少的情况下性能较高。Collections.UnmodifiableSet 用于在确定不让此数据结构不能修改的情况下使用,基本理论和List并发情况的论述中是一致的。