Java集合框架:Set(HashSet,LinkedHashSet,TreeSet)
阿新 • • 發佈:2019-01-24
Set概述
Set幾乎都是內部用一個Map來實現, 因為Map裡的KeySet就是一個Set,而value是假值,全部使用同一個Object。Set的特徵也繼承了那些內部Map實現的特徵。
HashSet
1. 定義
package java.util; public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable { private transient HashMap<E,Object> map; private static final Object PRESENT = new Object(); public HashSet() { map = new HashMap<>(); } //其餘省略 }
2. 概述
HashSet是基於HashMap來實現的,操作很簡單,更像是對HashMap做了一次“封裝”,而且只使用了HashMap的key來實現各種特性,而HashMap的value始終都是PRESENT。
HashSet不允許重複(HashMap的key不允許重複,如果出現重複就覆蓋),允許null值,非執行緒安全。
羅列幾個主要方法:
public Iterator<E> iterator() { return map.keySet().iterator(); } public int size() { return map.size(); } public boolean isEmpty() { return map.isEmpty(); } public boolean contains(Object o) { return map.containsKey(o); } public boolean add(E e) { return map.put(e, PRESENT)==null; } public boolean remove(Object o) { return map.remove(o)==PRESENT; } public void clear() { map.clear(); }
3. 使用
案例1:
Set<String> set = new HashSet<>(); set.add("s2"); set.add("s3"); set.add("s4"); set.add("s2"); set.add("s5"); set.add("s1"); set.add(null); set.add("s21"); set.add("sw2"); set.add("s2"); for(String i:set) System.out.println(i); System.out.println(set);
輸出:
null
s2
s1
sw2
s21
s5
s3
s4
[null, s2, s1, sw2, s21, s5, s3, s4]
LinkedHashSet
1. 定義(整個LinkedHashSet的程式碼)
package java.util;
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
private static final long serialVersionUID = -2851667679971038690L;
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);
}
}
2. 概述
HashSet有4個共有的建構函式:
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);
}
還有一個包級私有的建構函式:
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
這個建構函式就是LinkedHashSet的關鍵,整個LinkedHashSet的四個建構函式全部都是呼叫了HashSet中的這個包級私有的建構函式(建構函式中的dummy就是標記,無實用,為了實現方法的過載而已),也就是說LinkedHashSet就是基於LinkedHashMap實現的。
3. 使用
案例2:
Set<String> set = new LinkedHashSet<>();
set.add("s2");
set.add("s3");
set.add("s4");
set.add("s2");
set.add("s5");
set.add("s1");
set.add(null);
set.add("s21");
set.add("sw2");
set.add("s2");
for(String i:set)
System.out.println(i);
System.out.println(set);
輸出:
s2
s3
s4
s5
s1
null
s21
sw2
[s2, s3, s4, s5, s1, null, s21, sw2]
允許null值,保留插入順序,非執行緒安全。
TreeSet
1. 定義
package java.util;
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
{
private transient NavigableMap<E,Object> m;
private static final Object PRESENT = new Object();
public TreeSet() {
this(new TreeMap<E,Object>());
}
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
//其餘省略
}
2. 概述
TreeSet的內部基於TreeMap實現,同樣value永遠為PRESENT.
案例3:
Set<String> set = new TreeSet<String>();
set.add("s2");
set.add("s3");
set.add("s4");
set.add("s2");
set.add("s5");
set.add("s1");
// set.add(null);
set.add("s21");
set.add("sw2");
set.add("s2");
for(String i:set)
System.out.println(i);
System.out.println(set);
執行結果:
s1
s2
s21
s3
s4
s5
sw2
[s1, s2, s21, s3, s4, s5, sw2]
不允許重複,不允許null值(如果有基於null的比較器,就可以允許為null),預設按升序排列。
案例4(其中的Person2詳細見《Comparable與Comparator淺析》):
Set<Person2> set = new TreeSet<Person2>(new Comparator<Person2>(){
@Override
public int compare(Person2 o1, Person2 o2)
{
if(o1==null || o2==null)
return 0;
return o1.getAge()-o2.getAge();
}
});
Person2 p1 = new Person2("zzh",18);
Person2 p2 = new Person2("jj",17);
Person2 p3 = new Person2("qq",19);
Person2 p4 = new Person2(null,19);
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
System.out.println(set);
輸出結果:[jj:17, zzh:18, qq:19]
可以看到不是強制性要求TreeSet的鍵為null。
參考資料:
歡迎支援《RabbitMQ實戰指南》以及關注微信公眾號:朱小廝的部落格。