JAVA基礎之Set接口


個人理解:

  Set接口是Collection接口的子類,其繼承了所有方法,HashSet集合則實現了Set接口,其內部存儲數據時依靠哈希表,一個類似數組和鏈表的結合體。設置空集合時,存在默認的容量和加載因子,再用HashSet對象調用add方法時,其實是先比較其Hash值,若是沒有的話,則直接添加到集合中,若有的話,則再equals下比較其內容(因為有可能內容不一樣,但是其Hash值一樣),若是內容不一樣,則在這個地址下添加(鏈式),若是一樣的話,則丟掉。注意就保證了其的唯一性。(以后定義變量時,都需要重寫其hashcode和equals方法)至於LinkedHashSet則在HashSet基礎上保證了其的有序性(取出和存入順序一樣)。

  至此在用eclipse進行編寫java代碼時,在創建了私有屬性后,需要將下圖里get、set方法(第二行),hashCode和equals(第四行),toString(第五行),及倒數第二行的構造方法點出來(其中構造方法中包括兩種:有參和無參的,需要選擇好后點兩次)

一、Set接口:

1、Set接口介紹:

Set方法和Collection方法基本一致,通過元素的equals方法,來判斷是否為重復元素。

2、HashSet集合:

此類實現Set接口,由哈希表支持(實際上是個HashMap集合,是數組和鏈表的結合體)。HashSet集合不能保證迭代順序與元素的存儲順序相同。

3、HashSet集合存儲數據的結構:

哈希表:

  哈希表底層,使用的也是數組機制數組中也存放對象,而這些對象往數組中存放時的位置比較特殊,當需要把這些對象給數組中存放時,那么會根據這些對象的特有數據結合相應的算法,計算出這個對象在數組中的位置,然后把這個對象存放在數組中。而這樣的數組就稱為哈希數組,即就是哈希表。

   public HashSet()

      構造一個新的空 set,其底層 HashMap 實例的默認初始容量是 16,加載因子是 0.75。

    (當容量到16*0.75時,會再開16個的容量)

  當向哈希表中存放元素時,需要根據元素的特有數據結合相應的算法,這個算法其實就是Object類中的hashCode方法。

 

public int hashCode() {
        int h = hash;  //value是定義的字符數組 ,hash開始為0
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

  由於任何對象都是Object類的子類,所以任何對象有擁有這個方法。即就是在給哈希表中存放對象時,會調用對象的hashCode方法,算出對象在表中的存放位置,這里需要注意,如果兩個對象hashCode方法算出結果一樣,這樣現象稱為哈希沖突,這時會調用對象的equals方法,比較這兩個對象是不是同一個對象,如果equals方法返回的是true,那么就不會把第二個對象存放在哈希表中,如果返回的是false,就會把這個值存放在哈希表中。

可以理解為:

  當你用HashSet對象調用add方法時,它會去你存入的值的類型的那個類里調用它的HashCode方法,計算該對象內容的hash值;

  計算完成后就會去容器中找有沒有該hash值對應的值,沒有的話,則把該元素添加到容器中去。如果有的話,再調用要存入值的類型的類中的equals方法比較內容。如果內容也一樣,就丟掉這個值,不存入容器。如果內容不一樣,則存入容器。

public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;

   總結:保證HashSet集合元素的唯一,其實就是根據對象的hashCode和equals方法來決定的。如果我們往集合中存放自定義的對象,那么保證其唯一,就必須復寫hashCode和equals方法建立屬於當前對象的比較方式。

4、HashSet存儲自定義類型元素:

  給HashSet中存放自定義類型元素時,需要重寫對象中的hashCode和equals方法,建立自己的比較方式,才能保證HashSet集合中的對象唯一

5、LinkedHashSet介紹:

  在HashSet下面有一個子類LinkedHashSet,它是鏈表和哈希表組合的一個數據存儲結構,LinkedHashSet集合保證元素的存入和取出的順序。

二、判斷集合元素唯一的原理:

1、ArrayList的contains方法判斷元素是否重復原理:

  ArrayList的contains方法會使用調用方法時,傳入的元素的equals方法依次與集合中的舊元素所比較,從而根據返回的布爾值判斷是否有重復元素。此時,當ArrayList存放自定義類型時,由於自定義類型在未重寫equals方法前,判斷是否重復的依據是地址值,所以如果想根據內容判斷是否為重復元素,需要重寫元素的equals方法。

2、HashSet的add 、contains等方法判斷元素是否重復原理:

  Set集合不能存放重復元素,其添加方法在添加時會判斷是否有重復元素,有重復不添加,沒重復則添加。

  HashSet集合由於是無序的,其判斷唯一的依據是元素類型的hashCode與equals方法的返回結果。規則如下:

  先判斷新元素與集合內已經有的舊元素的HashCode值

①、 如果不同,說明是不同元素,添加到集合。

②、如果相同,再判斷equals比較結果。返回true則相同元素;返回false則不同元素,添加到集合。

  所以,使用HashSet存儲自定義類型,如果沒有重寫該類的hashCode與equals方法,則判斷重復時,使用的是地址值,如果想通過內容比較元素是否相同,需要重寫該元素類的hashcode與equals方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM