Java Set接口及常用實現(xiàn)類總結(jié)
前言
Collection的另一個子接口就是Set,他并沒有我們List常用,并且自身也沒有一些額外的方法,全是繼承自Collection中的,因此我們還是簡單總結(jié)一下,包括他的常用實現(xiàn)類HashSet、LinkedHashSet、TreeSet的總結(jié)!
概述
- Set 接口是 Collection 的子接口, set 接口沒有提供額外的方法。
- Set 集合不允許包含相同的元素,如果試把兩個相同的元素加入同一個
Set 集合中,則添加操作失敗。 - Set 判斷兩個對象是否相同不是使用 == 運算符,而是根據(jù)equals()方法。
Set 無序性與不可重復(fù)性的理解
無序性
不等于隨機性。
public static void main(String[] args) {
Set set = new HashSet();
set.add("aniu");
set.add(666);
set.add("yyds");
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}

可以看到,他遍歷輸出的結(jié)果不同于元素添加順序。但千萬不要認為這就是無序性,這一點你可以對比LinkedHashSet,他也是無序的,但他區(qū)別于HashSet,他可以按照添加順訊遍歷Set。因此,這里無序性要從底層存儲數(shù)據(jù)的角度理解:Set存儲的數(shù)據(jù)在底層數(shù)組中并非按照數(shù)組索引的順序添加,而是根據(jù)數(shù)據(jù)的哈希值。
不可重復(fù)性
保證添加的元素按照equals()判斷時,不能返回True,即相同的元素只能添加一個。
需要注意的是,對于自定義類實現(xiàn)的對象,一定要重寫hashcode和equals方法才能保證判斷他們是否相等。
可以看下面這段代碼:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* @Author:Aniu
* @Date:2023/1/5 17:24
* @description TODO
*/
public class Demo {
public static void main(String[] args) {
Set set = new HashSet();
set.add("aniu");
set.add(666);
set.add("yyds");
set.add(new Stu("aniu",21));
set.add(new Stu("aniu",21));
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
class Stu{
String name;
int age;
public Stu(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Stu{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Stu)) return false;
Stu stu = (Stu) o;
if (age != stu.age) return false;
return name != null ? name.equals(stu.name) : stu.name == null;
}
}

可以發(fā)現(xiàn)我們之只重寫equals是不行的!
重寫hashcode后再看結(jié)果:
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}

可以看到成功去掉了自定義對象的重復(fù)。這個和Set的底層存儲原理有關(guān),我們下面會寫到!
Set 接口常用實現(xiàn)類
HashSet
作為Set接口的主要實現(xiàn)類,他是線程不安全的,可以存儲null值!
HashSet中元素的添加過程
我們以HashSet為例,來大概說一下Set元素的添加過程:
我們向 Hashset 中添加元素 a ,首先調(diào)用元素 a 所在類的 hashcode ()方法,計算元素 a 的哈希值,此哈希值接著通過某種算法計算出 HashSet 底層數(shù)組中的存放位置(即為:索引位置),判斷數(shù)組此位置上是否已經(jīng)有元素:
1.如果此位置上沒有其他元素,則元素 a 添加成功。
2.如果此位置上有其他元素(或以鏈表形式存在的多個元素),則比較元素a與元素 b 的 hash 值:
a.如果 hash 值不相同,則元素 a 添加成功。
b.如果 hash 值相同,進而需要調(diào)用元素 a 所在類的 equals ()方法:
- equals ()返回 true ,元素 a 添加失敗
- equaLs ()返回 false ,則元素 a 添加成功。
對于添加成功的而言,如果通過hash值計算出的數(shù)組索引相同,則元素 a 與已經(jīng)存在指定索引位置上數(shù)據(jù)以鏈表的方式存儲。

這也就是上面不可重復(fù)性里寫到的,對于自定義類實現(xiàn)的對象,一定要重寫hashcode和equals方法才能保證判斷他們是否相等。
這里源碼就不分析了,因為 HashSet的底層是HashMap,我們后面會總結(jié)HashMap的源碼分析!
LinkedHashSet
是HashSet的子類,遍歷其內(nèi)部數(shù)據(jù)時,可以按照添加的順序遍歷!
public static void main(String[] args) {
Set set = new LinkedHashSet();
set.add("aniu");
set.add(666);
set.add("yyds");
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}

LinkedHashSet為什么可以按照添加的元素順序來遍歷呢,看下面這張圖就行了:

LinkedHashSet在原有HashSet的基礎(chǔ)上提供了雙向鏈表,保證了便歷時的順序輸出!
對于頻繁的便利操作,LinkedHashSet的效率高于HashSet!
TreeSet
可以按照添加的元素的指定屬性進行排序,因此,他要求添加的元素是同一數(shù)據(jù)類型!
public class Demo {
public static void main(String[] args) {
Set set = new TreeSet();
set.add(3);
set.add(21);
set.add(15);
set.add(6);
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}

對于自定義類的對象,就需要我們前面總結(jié)的自然排序和定制排序了,這里不再寫案例!
那再看看TreeSet的存儲結(jié)構(gòu):

以上就是Java Set接口及常用實現(xiàn)類總結(jié)的詳細內(nèi)容,更多關(guān)于Java Set接口的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于Spring?Data?Jpa?自定義方法實現(xiàn)問題
這篇文章主要介紹了關(guān)于Spring?Data?Jpa?自定義方法實現(xiàn)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
Java匿名內(nèi)部類和Lambda(->) 的多種寫法總結(jié)
這篇文章主要和大家分享一下Java匿名內(nèi)部類和Lambda(->) 的多種寫法,文中的示例代碼講解詳細,對我們學(xué)習(xí)Java有一定幫助,需要的可以先看一下2022-07-07
使用java實現(xiàn)http多線程斷點下載文件(二)
下載工具我想沒有幾個人不會用的吧,前段時間比較無聊,花了點時間用java寫了個簡單的http多線程下載程序,我實現(xiàn)的這個http下載工具功能很簡單,就是一個多線程以及一個斷點恢復(fù),當然下載是必不可少的,需要的朋友可以參考下2012-12-12
springboot+mybatis配置控制臺打印sql日志的方法
這篇文章主要介紹了springboot+mybatis配置控制臺打印sql日志的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
spring?boot?導(dǎo)出數(shù)據(jù)到excel的操作步驟(demo)
這篇文章主要介紹了spring?boot?導(dǎo)出數(shù)據(jù)到excel的實現(xiàn)步驟,文中通過打開一個平時練習(xí)使用的springboot的demo給大家詳細介紹,需要的朋友可以參考下2022-03-03

