1. 程式人生 > 其它 >java開技術SE進階之Set介面分析

java開技術SE進階之Set介面分析

Set介面

  • Set介面是Collection的子介面,set介面沒有提供額外的方法。
  • Set 集合不允許包含相同的元素,如果試把兩個相同的元素加入同一個 Set 集合中,則新增操作失敗。
  • Set 判斷兩個物件是否相同不是使用 == 運算子,而是根據 equals 方法。因此存放到Set集合中的元素一定要注意equals方法的重寫。

Set的常用實現類有:HashSet、TreeSet、LinkedHashSet。

HashSet

1、概述

  • HashSet 是 Set 介面的典型實現,大多數時候使用 Set 集合時都使用這個實現類。
  • HashSet 按 Hash 演算法來儲存集合中的元素,因此具有很好的存取和查詢效能。
  • HashSet 集合判斷兩個元素相等的標準:兩個物件通過 hashCode() 方法比較相等,並且兩個物件的 equals() 方法返回值也相等。
    • 當向 HashSet 集合中存入一個元素時,HashSet 會呼叫該物件的 hashCode() 方法來得到該物件的 hashCode 值,然後根據 hashCode 值,通過某種雜湊函式決定該物件在 HashSet 中的儲存位置。(這個雜湊函式會與底層陣列的長度相計算得到在陣列中的下標,並且這種雜湊函式計算還儘可能保證能均勻儲存元素,越是雜湊分佈,該雜湊函式設計的越好)
    • 如果兩個元素的hashCode()值相等,會再繼續呼叫equals方法,如果equals方法結果為true,新增失敗,如果為false,那麼會儲存該元素,但是該陣列的位置已經有元素了,那麼會通過連結串列的方式繼續連結。
  • HashSet 具有以下特點:
    • 不能保證元素的排列順序
    • HashSet 不是執行緒安全的
    • 集合元素可以有一個是 null

底層也是陣列,初始容量為16,當如果使用率超過0.75,(16*0.75=12)就會擴大容量為原來的2倍。(16擴容為32,依次為64,128….等)

結論:存放到Set集合中的元素一定要注意equals和hashcode方法的重寫。

2、hashCode和equals方法

重寫equals()方法的原則:

  • 對稱性:如果equals(y)返回是“true”,那麼y.equals(x)也應該返回是“true”。
  • 自反性:equals(x)必須返回是“true”。
  • 類推性:如果equals(y)返回是“true”,而且y.equals(z)返回是“true”,那麼z.equals(x)也應該返回是“true”。
  • 一致性:如果equals(y)返回是“true”,只要x和y內容一直不變,不管你重複x.equals(y)多少次,返回都是“true”。
  • 任何情況下,equals(null),永遠返回是“false”;x.equals(和x不同型別的物件)永遠返回是“false”。

重寫 hashCode() 方法的基本原則

  • 在程式執行時,同一個物件多次呼叫 hashCode() 方法應該返回相同的值
  • 當兩個物件的 equals() 方法比較返回 true 時,這兩個物件的 hashCode() 方法的返回值也應相等
  • 物件中用作 equals() 方法比較的屬性Field,都應該用來計算 hashCode 值

LinkedHashSet

LinkedHashSet 是 HashSet 的子類

LinkedHashSet 根據元素的 hashCode 值來決定元素的儲存位置,但它同時使用連結串列維護元素的次序,這使得元素看起來是以插入順序儲存的。

LinkedHashSet插入效能略低於 HashSet,但在迭代訪問 Set 裡的全部元素時有很好的效能。

LinkedHashSet 不允許集合元素重複。

TreeSet

TreeSet 是 SortedSet 介面的實現類,TreeSet 可以確保集合元素處於排序狀態。

TreeSet 兩種排序方法:自然排序和定製排序。預設情況下,TreeSet 採用自然排序。

1、自然排序

TreeSet 會呼叫集合元素的 compareTo(Object obj) 方法來比較元素之間的大小關係,然後將集合元素按升序排列,如果試圖把一個物件新增到 TreeSet 時,則該物件的類必須實現 Comparable 介面。實現 Comparable 的類必須實現 compareTo(Object obj) 方法,兩個物件即通過 compareTo(Object obj) 方法的返回值來比較大小。

向 TreeSet 中新增元素時,只有第一個元素無須比較compareTo()方法,後面新增的所有元素都會呼叫compareTo()方法進行比較。

因為只有相同類的兩個例項才會比較大小,所以向 TreeSet 中新增的應該是同一個類的物件

對於 TreeSet 集合而言,它判斷兩個物件是否相等的唯一標準是:兩個物件通過 compareTo(Object obj) 方法比較返回值

當需要把一個物件放入 TreeSet 中,重寫該物件對應的 equals() 方法時,應保證該方法與 compareTo(Object obj) 方法有一致的結果:如果兩個物件通過 equals() 方法比較返回 true,則通過 compareTo(Object obj) 方法比較應返回 0。否則讓人難以理解。

Comparable 的典型實現:

  • BigDecimal、BigInteger 以及所有的數值型對應的包裝類:按它們對應的數值大小進行比較
  • Character:按字元的 unicode值來進行比較
  • Boolean:true 對應的包裝類例項大於 false 對應的包裝類例項
  • String:按字串中字元的 unicode 值進行比較
  • Date、Time:後邊的時間、日期比前面的時間、日期大

2、定製排序

  • TreeSet的自然排序是根據集合元素的大小,進行元素升序排列。如果需要定製排序,比如降序排列,可通過Comparator介面的幫助。需要重寫compare(T o1,T o2)方法。利用int compare(T o1,T o2)方法,比較o1和o2的大小:如果方法返回正整數,則表示o1大於o2;如果返回0,表示相等;返回負整數,表示o1小於o2。
  • 要實現定製排序,需要將實現Comparator介面的例項作為形參傳遞給TreeSet的構造器。
  • 此時,仍然只能向TreeSet中新增型別相同的物件。否則發生ClassCastException異常。
  • 使用定製排序判斷兩個元素相等的標準是:通過Comparator比較兩個元素返回了0。
  • 當使用具有與 equals 不一致的強行排序能力的 Comparator 對有序 set(或有序對映)進行排序時,應該小心謹慎。假定一個帶顯式 Comparator c 的有序 set(或有序對映)與從 set S 中抽取出來的元素(或鍵)一起使用。如果 c 強行對 S 進行的排序是與 equals 不一致的,那麼有序 set(或有序對映)將是行為“怪異的”。

3、結論

  • 放到TreeSet集合中的元素必須是同一個型別的元素
  • 放到TreeSet集合中的元素必須實現Comparable介面,重寫compareTo(Object obj)方法,並且需要使得equals方法的與compareTo方法結果一直,即如果兩個物件通過 equals() 方法比較返回 true,則通過 compareTo(Object obj) 方法比較應返回 0。
  • TreeSet的自然排序是根據集合元素的大小,進行元素升序排列。如果需要定製排序,比如降序排列,可以將實現Comparator介面的例項作為形參傳遞給TreeSet的構造器,那麼新增元素時,將呼叫compare(T o1,T o2)方法作為排序依據。同時也應該注意equals方法與compare(T o1,T o2)方法的結果一致。

瞭解java培訓開發技術知識,關注我,有更多精彩內容與您分享!

文章轉載連結:http://www.atguigu.com/jsfx/12353.html