Java集合之Set接口及其實(shí)現(xiàn)類精解
Set接口概述
1、Set接口是Collection的子接口,set接口沒有定義額外的方法,使用的都是Collection接口中的方法。
2、Set 集合不允許包含相同的元素,如果試把兩個(gè)相同的元素加入同一個(gè)Set 集合中,則添加操作失敗。
3、Set:存儲(chǔ)無序的、不可重復(fù)的數(shù)據(jù)
(以HashSet為例說明)
①無序性:不等于隨機(jī)性。存儲(chǔ)的數(shù)據(jù)在底層數(shù)組中并非按照數(shù)組索引的順序添加,而是根據(jù)數(shù)據(jù)的哈希值。
②不可重復(fù)性:保證添加的元素按照equals()判斷時(shí),不能返回true。即:相同的元素只能添加一個(gè)。
HashSet實(shí)現(xiàn)類
1、HashSet 具有以下特點(diǎn):
①不能保證元素的排列順序
②HashSet 不是線程安全的
③集合元素可以是 null
2、HashSet 集合判斷兩個(gè)元素相等的標(biāo)準(zhǔn)
兩個(gè)對(duì)象通過 hashCode() 方法比較相等,并且兩個(gè)對(duì)象的 equals() 方法返回值也相等。因此對(duì)于存放在Set容器中的對(duì)象,對(duì)應(yīng)的類一定要重寫equals()和hashCode()方法,以實(shí)現(xiàn)對(duì)象相等規(guī)則,即:“相等的對(duì)象必須具有相等的散列碼”。
3、向HashSet中添加元素的過程
我們向HashSet中添加元素a,首先調(diào)用元素a所在類的hashCode()方法,計(jì)算元素a的哈希值,此哈希值接著通過某種算法計(jì)算出在HashSet底層數(shù)組中的存放位置(索引位置)。接著判斷數(shù)組此位置上是否已經(jīng)有元素:
如果此位置上沒有其他元素,則元素a添加成功?!?gt;情況1
如果此位置上有其他元素b(或以鏈表形式存在多個(gè)元素),則比較元素a與元素b的hash值:
如果hash值不相同,則元素a添加成功?!?gt; 情況2
如果hash值相同,進(jìn)而需要調(diào)用元素a所在類的equals()方法:
如果equals()返回true,元素a添加失敗
如果equals()返回false,則元素a添加成功?!?gt;情況3
對(duì)于添加成功的情況2和情況3而言:元素a與已經(jīng)存在指定索引位置上數(shù)據(jù)以鏈表的方式存儲(chǔ)。(七上八下)
jdk 7 : 新來元素a放到數(shù)組中,指向已存在的舊元素。
jdk 8 : 已存在的舊元素在數(shù)組中,指向新來元素a
底層為“數(shù)組+鏈表”,數(shù)組初始容量為16,當(dāng)如果使用率超過0.75(16*0.75=12)就會(huì)擴(kuò)大容量為原來的2倍。(16擴(kuò)容為32,依次為64,128…等)
重寫equals()方法的時(shí)候一般都需要同時(shí)復(fù)寫hashCode()方法。通常參與計(jì)算hash值的對(duì)象的屬性也應(yīng)該參與到equals()中進(jìn)行計(jì)算
LinkedHashSet實(shí)現(xiàn)類
1、LinkedHashSet 是 HashSet 的子類,也是根據(jù)元素的 hashCode 值來決定元素的存儲(chǔ)位置,但它同時(shí)使用雙向鏈表維護(hù)元素的次序,這使得元素看起來是以插入順序保存的。
2、LinkedHashSet插入性能略低于 HashSet,但在迭代訪問(遍歷) Set 里的元素時(shí)有很好的性能。
3、LinkedHashSet 不允許集合元素重復(fù)。
TreeSet實(shí)現(xiàn)類
1、TreeSet 是 SortedSet 接口的實(shí)現(xiàn)類,TreeSet 可以確保集合元素處于排序狀態(tài)。元素應(yīng)為相同類的對(duì)象。
2、TreeSet底層使用紅黑樹結(jié)構(gòu)存儲(chǔ)數(shù)據(jù)。
3、TreeSet 兩種排序方法:自然排序和定制排序。默認(rèn)情況下,TreeSet 采用自然排序。
4、自然排序
①TreeSet 會(huì)調(diào)用集合元素的 compareTo(Object obj) 方法來比較元素之間的大小關(guān)系,然后將集合元素按條件排列。如果試圖把一個(gè)對(duì)象添加到 TreeSet 時(shí),則該對(duì)象的類必須實(shí)現(xiàn) Comparable 接口。實(shí)現(xiàn) Comparable 的類必須重寫compareTo(Object obj) 方法,兩個(gè)對(duì)象通過compareTo(Object obj) 方法的返回值來比較大小。
②向 TreeSet 中添加元素時(shí),只有第一個(gè)元素?zé)o須比較compareTo()方法,后面添
加的所有元素都會(huì)調(diào)用compareTo()方法進(jìn)行比較。
③因?yàn)橹挥邢嗤惖膬蓚€(gè)實(shí)例才會(huì)比較大小,所以向 TreeSet 中添加的應(yīng)該是同
一個(gè)類的對(duì)象。
④對(duì)于 TreeSet 集合而言,它判斷兩個(gè)對(duì)象是否相等的唯一標(biāo)準(zhǔn)是兩個(gè)對(duì)象通過 compareTo(Object obj) 方法比較的返回值。
import java.util.Iterator; import java.util.TreeSet; /** * @Author: Yeman * @Date: 2021-09-16-16:48 * @Description: */ class Student implements Comparable{ String name; int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } @Override //姓名從小到大,年齡從大到小排列 public int compareTo(Object o) { if (o instanceof Student){ Student student = (Student) o; int nameResult = this.name.compareTo(student.name); if (nameResult == 0){ return -Integer.compare(this.age,student.age); }else { return nameResult; } }else throw new RuntimeException("類型不匹配"); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } } public class TreeSetTest { public static void main(String[] args) { TreeSet treeSet = new TreeSet(); treeSet.add(new Student("Tom",18)); treeSet.add(new Student("Tom",22)); treeSet.add(new Student("jim",18)); treeSet.add(new Student("Anne",19)); treeSet.add(new Student("Lily",25)); treeSet.add(new Student("LiLei",25)); Iterator iterator = treeSet.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } } }
5、定制排序
①定制排序,通過Comparator接口來實(shí)現(xiàn),需要重寫compare(T o1,T o2)方法。
②要實(shí)現(xiàn)定制排序,需要將實(shí)現(xiàn)Comparator接口的實(shí)例作為形參傳遞給TreeSet的構(gòu)造器。
③仍然只能向TreeSet中添加類型相同的對(duì)象。否則發(fā)生ClassCastException異常。
④使用定制排序判斷兩個(gè)元素相等的標(biāo)準(zhǔn)是:通過Comparator比較兩個(gè)元素返回了0。
import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; /** * @Author: Yeman * @Date: 2021-09-16-16:48 * @Description: */ class Student{ String name; int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } } public class TreeSetTest { public static void main(String[] args) { Comparator com = new Comparator() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof Student && o2 instanceof Student) { Student student1 = (Student) o1; Student student2 = (Student) o2; return Integer.compare(student1.age, student2.age); } else throw new RuntimeException("類型不匹配"); } }; TreeSet treeSet = new TreeSet(com); treeSet.add(new Student("Tom",18)); treeSet.add(new Student("Tom",22)); treeSet.add(new Student("jim",18)); treeSet.add(new Student("Anne",19)); treeSet.add(new Student("Lily",25)); treeSet.add(new Student("LiLei",25)); Iterator iterator = treeSet.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } } }
到此這篇關(guān)于Java集合之Set接口及其實(shí)現(xiàn)類精解的文章就介紹到這了,更多相關(guān)Java Set接口內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java如何比較兩個(gè)對(duì)象并獲取不相等的字段詳解
這篇文章主要給大家介紹了關(guān)于Java如何比較兩個(gè)對(duì)象并獲取不相等的字段以及JAVA判斷(獲?。﹥蓚€(gè)相同對(duì)象不同的數(shù)據(jù)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-11-11windows下java -jar 后臺(tái)運(yùn)行以及殺死后臺(tái)進(jìn)程的操作
這篇文章主要介紹了windows下java -jar 后臺(tái)運(yùn)行以及殺死后臺(tái)進(jìn)程的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12spring 重復(fù)注解和aop攔截的實(shí)現(xiàn)示例
本文主要介紹了spring 重復(fù)注解和aop攔截的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-08-08如何使用Spring-Test對(duì)Spring框架進(jìn)行單元測(cè)試
這篇文章主要介紹了如何使用Spring-Test對(duì)Spring框架進(jìn)行單元測(cè)試,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09Spring MVC---數(shù)據(jù)綁定和表單標(biāo)簽詳解
本篇文章主要介紹了Spring MVC---數(shù)據(jù)綁定和表單標(biāo)簽詳解,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01