一、概述
- Set集合與Collection集合基本相同,沒有提供額外的方法。實際上Set就是Collection,只是行為略有不同(Set不允許包含重復元素)。
- Set不允許包含重復元素,如果視圖把兩個相同的元素加入到同一個Set集合中,則會添加失敗,add()方法返回false,且新元素不會被加入。
- 加入Set的元素必須定義equals()方法以確保對象的唯一性。Set接口不保證維護元素的次序。
二、HashSet
2.1 概述
- HashSet是Set的典型接口實現,實現了Set接口中所有方法,并沒有額外添加方法
- HashSet是針對了HashMap進行封裝,其中Set中存儲的元素是存儲在HashMap的Key,但是Value值在Java和Android中實現有不同的表現,JDK1.8中使用的是一個固定的Object來當值,而在Android中則是使用HashMap本來來作為值。
- 既然是對HashMap的封裝,那么必然也需要Set中存儲的元素需要實現equals()和hashCode()方法。
- 為快速查找而設計的Set
2.2 代碼
Java
private transient HashMap<E,Object> map;//封裝的HashMap
private static final Object PRESENT = new Object();//Map需要的Values值
//幾個構造函數,都調用了相對應的HashMap的構造函數來確保對HashMap的封裝
public HashSet() {
map = new HashMap<>();
}
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
//主要針對LinkedHashSet來封裝LinkedHashMap
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
//常用操作
public boolean add(E e) {//增
return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {//刪
return map.remove(o)==PRESENT;
}
public boolean contains(Object o) {//查
return map.containsKey(o);
}
public Iterator<E> iterator() {//遍歷
return map.keySet().iterator();
}
Android
transient HashMap<E, HashSet<E>> backingMap;//值的泛型時HashSet
//構造函數,調用的全是一個沒有修飾符的構造函數,子類調的也是這個
public HashSet() {
this(new HashMap<E, HashSet<E>>());
}
public HashSet(int capacity) {
this(new HashMap<E, HashSet<E>>(capacity));
}
public HashSet(int capacity, float loadFactor) {
this(new HashMap<E, HashSet<E>>(capacity, loadFactor));
}
public HashSet(Collection<? extends E> collection) {
this(new HashMap<E, HashSet<E>>(collection.size() < 6 ? 11 : collection
.size() * 2));
for (E e : collection) {
add(e);
}
}
HashSet(HashMap<E, HashSet<E>> backingMap) {
this.backingMap = backingMap;
}
//常用操作
@Override
public boolean add(E object) {//增
return backingMap.put(object, this) == null;
}
@Override
public boolean remove(Object object) {//刪
return backingMap.remove(object) != null;
}
@Override
public boolean contains(Object object) {//查詢,包含
return backingMap.containsKey(object);
}
@Override
public Iterator<E> iterator() {//遍歷
return backingMap.keySet().iterator();
}
三、LinkedTreeSet
3.1 概述
- 繼承自HashSet,是對LinkedHashMap的封裝
- 數據的遍歷順序是采用LinkedHashMap相關的遍歷順序
- 具有HashSet的查詢數據,且內部使用鏈表維護元素的順序,于是在使用迭代器遍歷Set是,結果會按元素插入的次序顯示。
3.2 代碼
構造函數都是調用父類的默認構造函數
Java
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
public LinkedHashSet() {
super(16, .75f, true);
}
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
}
Android
public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable,
Serializable {
public LinkedHashSet() {
super(new LinkedHashMap<E, HashSet<E>>());
}
public LinkedHashSet(int capacity) {
super(new LinkedHashMap<E, HashSet<E>>(capacity));
}
public LinkedHashSet(int capacity, float loadFactor) {
super(new LinkedHashMap<E, HashSet<E>>(capacity, loadFactor));
}
public LinkedHashSet(Collection<? extends E> collection) {
super(new LinkedHashMap<E, HashSet<E>>(collection.size() < 6 ? 11
: collection.size() * 2));
for (E e : collection) {
add(e);
}
}
}
四、TreeSet
4.1 概述
- TreeSet是NavigableSet 的實現類,NavigableSet是繼承SortedSet的接口,TreeSet默認是排序的。
- TreeSet為了保證是有序的序列,那么它的元素必須是可比較的,或者使用比較器來比較它的元素。
- TreeSet是對TreeMap進行封裝,那么TreeSet的底層數據結構也和TreeMap相同
4.2 代碼
Java
private transient NavigableMap<E,Object> m;//可排序的Map
private static final Object PRESENT = new Object();//Map的值
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
public TreeSet() {
this(new TreeMap<E,Object>());//初始化一個TreeMap
}
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));//初始化一個TreeMap
}
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
//常用方法
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
public boolean addAll(Collection<? extends E> c) {
// Use linear-time version if applicable
if (m.size()==0 && c.size() > 0 &&
c instanceof SortedSet &&
m instanceof TreeMap) {
SortedSet<? extends E> set = (SortedSet<? extends E>) c;
TreeMap<E,Object> map = (TreeMap<E, Object>) m;
Comparator<?> cc = set.comparator();
Comparator<? super E> mc = map.comparator();
if (cc==mc || (cc != null && cc.equals(mc))) {
map.addAllForTreeSet(set, PRESENT);
return true;
}
}
return super.addAll(c);
}
public boolean remove(Object o) {
return m.remove(o)==PRESENT;
}
public boolean contains(Object o) {
return m.containsKey(o);
}
//還有一些NavigableSet或者SortedMap方法,比如獲取第一個元素,最后一個元素,前一個元素,后一個元素等
//遍歷
public Iterator<E> iterator() {//正序遍歷
return m.navigableKeySet().iterator();
}
public Iterator<E> descendingIterator() {//倒序遍歷
return m.descendingKeySet().iterator();
}
Android
private transient NavigableMap<E, Object> backingMap;//需要封裝的對象
private transient NavigableSet<E> descendingSet;//倒序Set
TreeSet(NavigableMap<E, Object> map) {
backingMap = map;
}
public TreeSet() {
backingMap = new TreeMap<E, Object>();
}
public TreeSet(Collection<? extends E> collection) {
this();
addAll(collection);
}
public TreeSet(Comparator<? super E> comparator) {
backingMap = new TreeMap<E, Object>(comparator);
}
public TreeSet(SortedSet<E> set) {
this(set.comparator());
Iterator<E> it = set.iterator();
while (it.hasNext()) {
add(it.next());
}
}
//常用方法
@Override
public boolean add(E object) {
return backingMap.put(object, Boolean.TRUE) == null;
}
@Override
public boolean addAll(Collection<? extends E> collection) {
return super.addAll(collection);
}
@Override
public boolean contains(Object object) {
return backingMap.containsKey(object);
}
@Override
public boolean remove(Object object) {
return backingMap.remove(object) != null;
}
//遍歷
@Override
public Iterator<E> iterator() {
return backingMap.keySet().iterator();
}
public Iterator<E> descendingIterator() {
return descendingSet().iterator();
}
五、EnumSet
5.1 概述
- 專為枚舉設置的集合,后續會補充
六、總結
- 這幾種Set可以根據需要進行旋轉。
1.1 查詢操作較多時,并且忽略順序時,使用HashSet
1.2 查詢、遍歷操作較多時,并且需要順序是,可以使用LinkedHashSet
1.3 當只需要一個特定排序的集合時,這個排序如果需要自定義時,可以考慮使用TreeSet
1.4 插入、刪除等操作,在數據量比較小時考慮使用HashSet,不用特意去考慮
hashCode的算法,也能有較高的效率,如果數據量比較大時,可以考慮使用TreeSet畢竟TreeSet操作時間效率在O(logn)
1.5 具體選擇哪種集合,還需要寫測試代碼進行測試。 - Java中Set就是對相應的Map進行一層封裝,具體可以參考下方關于Map的文章
- 沒有3了......
其他文章
容器解析
ArrayList解析
LinkedList解析
TreeMap解析(上)
TreeMap解析(下)
HashMap解析
LinkedHasMap解析(下)
Set解析