Java集合詳解--什麼是Set
簡述
Set和List一樣,也繼承於Collection,是集合的一種。和List不同的是,Set內部實現是基於Map的,所以Set取值時不保證資料和存入的時候順序一致,並且不允許空值,不允許重複值。
然後我們來看下Set的繼承結構
可以看出,Set主要有2個實現方式,一個是TreeSet,另一個是HashSet
這個Set的特點,主要由其內部的Map決定的,可以負責人的說一句,Set就是Map的一個馬甲
HashSet和TreeSet
就如它的名字一樣,HashSet主要由HashMap實現
如果呼叫HashSet的無參建構函式,那麼就會使用預設的HashMap,初始化Size為16,擴張係數為0.75
//簡單看下HashMap的幾個主要資料執行操作都是間接的呼叫了內部的HashMap的資料操作
//比較有意思的是,從add()方法看出,HashSet的值是HashMap的key,
//HashMap的value是寫死的PRESENT
//所以遍歷HashSet的值,也就是遍歷HashMap的KeyEntry
/**
* Returns an iterator over the elements in this set. The elements
* are returned in no particular order.
*
* @return an Iterator over the elements in this set
* @see ConcurrentModificationException
*/
public Iterator<E> iterator() {
return map.keySet().iterator();
}
/**
* Returns the number of elements in this set (its cardinality).
*
* @return the number of elements in this set (its cardinality)
*/
public int size() {
return map.size();
}
/**
* Returns <tt>true</tt> if this set contains no elements.
*
* @return <tt>true</tt> if this set contains no elements
*/
public boolean isEmpty() {
return map.isEmpty();
}
/**
* Returns <tt>true</tt> if this set contains the specified element.
* More formally, returns <tt>true</tt> if and only if this set
* contains an element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* @param o element whose presence in this set is to be tested
* @return <tt>true</tt> if this set contains the specified element
*/
public boolean contains(Object o) {
return map.containsKey(o);
}
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
/**
* Removes the specified element from this set if it is present.
* More formally, removes an element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>,
* if this set contains such an element. Returns <tt>true</tt> if
* this set contained the element (or equivalently, if this set
* changed as a result of the call). (This set will not contain the
* element once the call returns.)
*
* @param o object to be removed from this set, if present
* @return <tt>true</tt> if the set contained the specified element
*/
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
/**
* Removes all of the elements from this set.
* The set will be empty after this call returns.
*/
public void clear() {
map.clear();
}
TreeSet和HashMap的處理方式相似,這裡就不重複展開,區別的地方是,TreeSet內部的是一顆紅黑樹,至於紅黑樹的特點,再下一章會詳細展開
comparator和comparable
由於Set的實現都基於Map,所以操作都十分簡單,所以在這章把Map會提到的comparator和comparable提前分析
直觀的翻譯我們也可以得出,這2個東西都是和排序有關。
comparator和comparable都是介面。
1.comparable
先來看看comparable
Comparable 介面強行對實現它的每個類的物件進行整體排序,Java稱這種排序為自然排序,對比於comparator,又稱為內部排序
Comparable介面只有一個方法
public int compareTo(T o);
對於需要排序的物件,只要繼承這個介面,實現這個compareTo()方法就可以了,(T o)代表傳入的資料,需要進行比較的物件。如果位於物件 o 之前,返回負值,如果兩個物件在排序中位置相同,則返回 0 ,如果位於物件 o 後面,則返回正值。
在註釋中又說到,希望把comparaTo()和equal()聯絡起來。因為這個2個方法都是對物件進行比較,如果這2個方法對同一個比較物件產生不同的結果,會造成邏輯上的困惑。
舉個例子,
class Test{
int compareFactor;
//setCompareFactor...getCompareFactor...
public int compareTo(T o){
if(o == null){
//這裡是註釋上建議這麼做的,如果傳入一個空值,需要丟擲一個異常
throw new RuntimeException ("test");
}
//如果相等,表示處於比較的同一個位置
if(this.compareFactor == ((Test)o).getCompareFactor()){
return 0;
} else if(this.compareFactor > ((Test)o).getCompareFactor()){
return 1;
} else {
return 0;
}
}
//使用的時候只要呼叫Collections或者Array的sort()方法就好了
Collections.sort(list);
2.Comparator
相對於Comparable ,comparator又稱為外部排序。對於一些已經封裝好的物件,我們在儘量不修改已有結構的基礎上,通過實現Comparator類來新建一個比較器,然後通過該比較器來對類進行排序。Comparator 介面其實就是一種策略模式的實踐
Comparator內部包含了2個方法
int compare(T o1, T o2);
boolean equals(Object obj);
由於所有java物件都繼承於Object,所以equals(Object obj)已經被實現了,我們只要實現compare(T o1, T o2)方法就好了。實現的思路和comparable一樣,只不過comparable是和自己比較,Comparator是對於兩個物件進行比較。
3.異同
Comparable是由物件自己實現的,一旦一個物件封裝好了,compare的邏輯也就定了,如果我們需要對同一個物件增加一個欄位的排序就比較麻煩,又要修改物件本身。比如淘寶的購買頁面,增加一種受歡迎度的排序,就需要修改物件內部compare方法。好處是對外部不可見,呼叫者無需知道排序邏輯,只要呼叫排序即可,類似於靜態繫結。
而Comparator由外部實現,比較靈活,爭對上述問題,只要新增一個Comparator即可。缺點是所有排序邏輯對外部暴露,需要物件外部實現。不過這裡的外部僅指物件的外部,也可以由API的開發者封裝好所有的Comparator,對呼叫者隱藏內部邏輯。好處是很靈活,隨時可以增加一種排序方法,只要物件內部欄位支援,類似動態繫結。
總結
在這一章節中簡單介紹了Set的結構,實現原理。Set是Map的一個馬甲,主要邏輯都交給Map實現。在下一章中,會詳細介紹Map的實現原理。
還介紹了與排序相關的兩個介面comparator和comparable