Java原始碼分析——java.util工具包解析(二)——HashSet、TreeSet、LinkedHashSet類解析
Set,即集合,與數學上的定義一樣,集合具有三個特點:
- 無序性:一個集合中,每個元素的地位都是相同的,元素之間是無序的。
- 互異性:一個集合中,任何兩個元素都認為是不相同的,即每個元素只能出現一次。
- 確定性:給定一個集合,任給一個元素,該元素或者屬於或者不屬於該集合,二者必居其一,不允許有模稜兩可的情況出現。
但是Java中的集合並不是嚴格意義上的集合,其中的TreeSet集合類並不滿足,因為它是有序的,除了無序性這一點,Java中的集合都嚴格滿足其它兩點。
在Java中將集合類的起源定義為Set介面,並由該介面擴展出其他具體的實現,它們之間的關係如下:
SortedSet介面繼承自Set介面,在其內部定義了排序的行為交由TreeSet實現排序的集合。在AbstractSet抽象類中,與AbstractList類一樣,為其子類提供對其自身的操作,即集合類操作,只是集合的內部操作,並沒有實現集合間的操作。
HashSet
HashSet類是滿足集合屬性的三個屬性的,插入到其內部的元素是有其hashcode值決定的,其內部的具體實現是由HashMap完成的,平時我們建立一個新的HashSet類,實際上是建立了一個HashMap來完成我們所需的操作,HashSet類的幾個構造方法如下:
private transient HashMap<E,Object> map;
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);
}
可見裡面都建立了HashMap物件,也就是說,HashSet是利用HashMap的不可重複性來完成集合的互斥性的,示例程式碼:
String s1=new String("1");
String s2=new String("1");
String s3=new String("1");
Set<String> set=new HashSet<>();
set.add(s1);
set.add(s2);
set.add(s3);
System.out.println(set.add(s1));//false
Iterator iterable=set.iterator();
while (iterable.hasNext()){
System.out.println(iterable.next());//輸出:1
}
System.out.println(s1.hashCode()==s2.hashCode());//true
HashMap是根據物件的hashcode值來判斷是否是同一個物件的,因為s1、s2、s3的值相同,所以它們的hashcode值也相同,在集合中加入s1與s2時加不進去。下面列出常用的方法:
//獲取迭代器
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();
}
TreeSet
TreeSet類是有序的集合類,它實現了SortedSet介面,但與HashSet類相同的是,它也是在內部委託給另外一個類來完成其功能的,這個類是TreeMap類,TreeMap類在其內部實現了紅黑樹,因此可以實現較快的排序:
public TreeSet() {
this(new TreeMap<E,Object>());
}
還可以直接返回第一個元素以及最後一個元素:
public E first() {
return m.firstKey();
}
public E last() {
return m.lastKey();
}
加入到TreeMap中的元素必須實現Comparable與Comparator介面,用來進行比較,其示例程式碼如下:
String s1=new String("1");
String s2=new String("3");
String s3=new String("2");
Set<String> set=new TreeSet<>();
set.add(s1);
set.add(s2);
set.add(s3);
Iterator iterable=set.iterator();
while (iterable.hasNext()) {
System.out.println(iterable.next());
}
//輸出為:1 2 3
LinkedHashSet
LinkedHashSet繼承自HashSet,它不同於HashSet裡面的元素是無序的,它是按照元素的插入順序來儲存元素的,也就是說它是線性的,其內部是呼叫類父類的構造方法:
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
採用了LinkedHashMap來實現其功能,LinkedHashMap是線性的HashMap,所以LinkedHashSet即為線性的。示例程式碼:
String s1=new String("1");
String s2=new String("32");
String s3=new String("243242");
Set<String> set=new HashSet<>();
set.add(s1);
set.add(s2);
set.add(s3);
Iterator iterable=set.iterator();
while (iterable.hasNext()) {
System.out.println(iterable.next());
}
//輸出:1 243242 32
Set<String> set2=new LinkedHashSet<>();
set2.add(s1);
set2.add(s2);
set2.add(s3);
Iterator iterable2=set2.iterator();
while (iterable2.hasNext()) {
System.out.println(iterable2.next());
}
//輸出:1 32 243242
總的來說,三者其實是Map類的一個封裝而已。