Java Set接口详细讲解 TreeSet的定制排序和自然排序
Set接口概述
Set實現類之一:HashSet
1 HashSet 是 Set 接口的典型實現,大多數時候使用 Set 集合時都使用這個實現類。
2 HashSet 按 Hash 算法來存儲集合中的元素,因此具有很好的存取、查找、刪除性能。
HashSet 具有以下特點:
不能保證元素的排列順序
HashSet 不是線程安全的
集合元素可以是 null
HashSet 集合判斷兩個元素相等的標準:兩個對象通過 hashCode() 方法比較相等,并且兩個對象的 equals() 方法返回值也相等。
對于存放在Set容器中的對象,對應的類一定要重寫equals()和hashCode(Object obj)方法,以實現對象相等規則。即:“相等的對象必須具有相等的散列碼”。
Set實現類之一:HashSet
向HashSet中添加元素的過程:
1 當向 HashSet 集合中存入一個元素時,HashSet 會調用該對象的 hashCode() 方法
來得到該對象的 hashCode 值,然后根據 hashCode 值,通過某種散列函數決定該對象在 HashSet 底層數組中的存儲位置。(這個散列函數會與底層數組的長度相計算得到在數組中的下標,并且這種散列函數計算還盡可能保證能均勻存儲元素,越是散列分布,該散列函數設計的越好)
2 如果兩個元素的hashCode()值相等,會再繼續調用equals方法,如果equals方法結果為true,添加失敗;如果為false,那么會保存該元素,但是該數組的位置已經有元素了,那么會通過鏈表的方式繼續鏈接。
如果兩個元素的 equals() 方法返回 true,但它們的 hashCode() 返回值不相等,hashSet 將會把它們存儲在不同的位置,但依然可以添加成功。
重寫 hashCode() 方法的基本原則
- 在程序運行時,同一個對象多次調用 hashCode() 方法應該返回相同的值。
- 當兩個對象的 equals() 方法比較返回 true 時,這兩個對象的 hashCode() 方法的返回值也應相等。
- 對象中用作 equals() 方法比較的 Field,都應該用來計算 hashCode 值。
重寫 equals() 方法的基本原則
以自定義的Customer類為例,何時需要重寫equals()? ? 當一個類有自己特有的“邏輯相等”概念,當改寫equals()的時候,總是
要改寫hashCode(),根據一個類的equals方法(改寫后),兩個截然不同的實例有可能在邏輯上是相等的,但是,根據Object.hashCode()方法,它們僅僅是兩個對象。因此,違反了“相等的對象必須具有相等的散列碼”。
結論:復寫equals方法的時候一般都需要同時復寫hashCode方法。通常參與計算hashCode的對象的屬性也應該參與到equals()中進行計算。
Set實現類之二:LinkedHashSet
- LinkedHashSet 是 HashSet 的子類
- LinkedHashSet 根據元素的 hashCode 值來決定元素的存儲位置,但它同時使用雙向鏈表維護元素的次序,這使得元素看起來是以插入順序保存的。
- LinkedHashSet插入性能略低于 HashSet,但在迭代訪問 Set 里的全部元素時有很好的性能。
- LinkedHashSet 不允許集合元素重復。
Set實現類之三:TreeSet
- TreeSet 是 SortedSet 接口的實現類,TreeSet 可以確保集合元素處于排序狀態。
- TreeSet底層使用樹結構存儲數據
- 新增的方法如下: (了解)
1 Comparator comparator()
2 Object first()
3 Object last()
4 Object lower(Object e)
5 Object higher(Object e)
6 SortedSet subSet(fromElement, toElement) 7SortedSet headSet(toElement)
8SortedSettailSet(fromElement)
TreeSet 兩種排序方法:自然排序和定制排序。默認情況下,TreeSet 采用自然排序
排 序—自然排序
自然排序: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。否則,讓人難以理解。
排 序—定制排序
TreeSet的自然排序要求元素所屬的類實現Comparable接口,如果元素所屬的類沒
有實現Comparable接口,或不希望按照升序(默認情況)的方式排列元素或希望按照其它屬性大小進行排序,則考慮使用定制排序。定制排序,通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。
User中的comareTo方法
//按照姓名從小到大排序@Overridepublic int compareTo(Object o) {if(o instanceof User){User user = (User)o;//return this.name.compareTo(user.name);int compare = this.name.compareTo(user.name);if(compare!=0){return compare;}else{return Integer.compare(this.age,user.age);}}else{throw new RuntimeException("類型不匹配!!");}} 新人創作打卡挑戰賽發博客就能抽獎!定制產品紅包拿不停!總結
以上是生活随笔為你收集整理的Java Set接口详细讲解 TreeSet的定制排序和自然排序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TCP 协议状态解析
- 下一篇: 华东交通大学2017年ACM双基程序设计