1. 程式人生 > >Java集合詳解--什麼是Set

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&nbsp;?&nbsp;e==null&nbsp;:&nbsp;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&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;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&nbsp;?&nbsp;e==null&nbsp;:&nbsp;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