Java中接口Set的特點及方法說明
接口Set的特點及方法
1、特點:無序,不可重復(fù);
2、實現(xiàn)類:添加的方法:
add(Object obj);addAll(Collection c);
Set中沒有修改的方法,可以間接修改,先刪除再添加;
刪除的方法:
remove(Object obj);removeAll(Collection c);retainAll(Collection c)僅保留set中那些包含在指定的Collection中的元素;clear()清除所有元素;
查詢的方法:
contains(Object obj)查詢set中是否包含指定元素,包含返回true;containsAll(Collection c)查詢set中是否包含指定的多個元素,全部包含返回true;isEmpty()判斷set是否為空,為空返回true;
3、set集合的遍歷:使用for循環(huán);
使用iterator迭代器:it.hasNext()如果有下一個元素,返回true;
it.next()返回下一個元素;it.remove()刪除迭代器返回的最后一個元素;
Set接口及其實現(xiàn)類
Set接口有兩個實現(xiàn)類
- 散列集合:HashSet(Hash算法)
- 樹集合:TreeSet(二叉樹算法)
Set接口:Set存儲元素是無序不可以重復(fù)的
HashSet:元素是否重復(fù)是依據(jù):元素自身equals比較進行判定的。TreeSet:元素是否重復(fù)是依據(jù):CompareTo方法返回是否為0。
因為Set接口也是Collection的子接口
所以也可以使用Collection實現(xiàn)的所有方法,其中常用的有:
- 添加:add()
- 刪除:remove()
- 檢查元素是否存在:contains(Object o)
- 迭代器:iterator()
1、TreeSet:樹狀集合、存放有序
語法:Set<E> set = new TreeSet<E>();
說明:TreeSet添加元素時,首先按照compareTo()進行比較,而TreeSet要想指定集合的存放順序,被排序的對象需實現(xiàn)Comparable接口,這個接口強行的對每個實現(xiàn)類對象進行整體的排序,這種排序稱為類的自然排序,這個接口有個抽象方法compareTo,該方法稱為自然排序的方法。
向TreeSet中添加的元素必須是同一個類的。(否則底層調(diào)用compareTo時會報類型轉(zhuǎn)換異常)
public class Person implements Comparable{
int id;
int age;
String name;
public Person(int id,int age,String name){
super();
this.id = id;
this.age = age;
this.name = name;
}
public String toString(){
return "Person [id = " + id + ", age = " + age + ", name = " + name + "]";
}
@Override
public int compareTo(Object o){//按照id排序
Person p;
if(o instanceof Pserson){
p = (Person)o;
}else{
return -1;//-1代表傳入的參數(shù)比我本身要小
}
int diff = this.id - p.id;
if(diff!=0){
diff = diff / Math.abs(diff);//差值除以本身絕對值,可以得到+1或-1的值。
}
return diff;
}
該compareTo方法是根據(jù)對象的id進行比較,也可以根據(jù)自己的需求自定義比較內(nèi)容:
this.id是當(dāng)前對象的ido.id是指定對象的id(也就是傳入對象的id)
調(diào)用sort方法時可以自定義升序或降序:
- 升序:this.id - o.id(this.id < o.id 結(jié)果為負(fù)、this.id > o.id 結(jié)果為正,this.id = o.id 結(jié)果為0)
- 降序:o.id - this.id(this.id < o.id 結(jié)果為正、this.id < o.id 結(jié)果為負(fù),this.id = o.id 結(jié)果為0)
上述代碼中,我們使用的是this.id - o.id,所以我們是升序排序的(默認(rèn)情況就是升序排序的)。
import java.util.Set;
import java.util.TreeSet;
public class Demo{
public static void main(String[] args){
Set set = new TreeSet();
Person p1 = new Person(1,18,"小明");
Person p2 = new Person(2,5,"小強");
Person p3 = new Person(3,20,"小張");
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p3);//重復(fù)的元素不會被添加到集合中
System.out.println(set.size());
Iterator it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
compareTo方法就是為了實現(xiàn)Comparable接口而存在的,而實現(xiàn)Comparable接口就是為了可以直接使用sort()方法對該對象進行自定義排序。
注意:TreeSet是不能存在null元素(HashSet是可以存儲null值的),向TreeSet中添加元素時,首先按照compareTo()進行比較,元素底層調(diào)用compareTo方法時會報空指針異常。
2、HashSet:散列集合、高效快速
語法:Set<E> set = new HashSet<E>();
說明:HashSet存儲的對象,應(yīng)該重寫hashCode()和equals()兩個方法,在添加元素的時候會根據(jù)我們重寫hashCode()方法計算元素的hash值,根據(jù)哈希值計算元素存儲的位置(哈希地址),如果該哈希地址沒有元素則會直接添加成功,如果該位置有其他元素會根據(jù)equals方法判斷是否為同一個對象,如果結(jié)果返回true則不會添加,如果為false則會以鏈表的形式追加到該哈希地址處。(底層根據(jù)HashMap實現(xiàn))
在不指定泛型的情況下可以為不同的類型的值;
public class Person{
int id;
String name;
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
//重寫hashCode方法只根據(jù)id進行計算hash值
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
//重寫equals方法
@Override
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 (id != other.id)
return false;
return true;
}
//重寫toString方法,方便在我們輸出的時候查看
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + "]";
}
}
public class Demo{
public static void main(String[] args){
Set set = new HashSet();
Person p1 = new Person(1,"小明");
Person p2 = new Person(2,"小張");
Person p3 = new Person(3,"小李");
set.add(p1);
set.add(p2);
set.add(p3);
//在我們添加成功以后修改其決定hash值的id
p2.id = 5;
//在刪除時會導(dǎo)致刪除不掉(如果修改的是name則不會出現(xiàn)刪除不掉的效果)
//因為之前的元素存儲在id為2計算的哈希地址的位置,現(xiàn)在是去id為5計算的哈希地址出去刪除,所以刪除不掉
//set.remove(p2);
//會添加到id為5計算的哈希地址,所以會添加成功(雖然屬性相同,但是之前的是存儲在根據(jù)id為2計算的哈希地址位置)
set.add(p2);
//當(dāng)我們繼續(xù)添加的時候,equals返回的是true,所以不會添加成功
set.add(p2);
//此時創(chuàng)建一個id為2的對象繼續(xù)添加
Person p4 = new Person(2,"小張");
set.add(p4);//會添加id為2計算的哈希地址位置,雖然該位置有元素,但是之前的元素已經(jīng)被修改了,所以會添加成功
System.out.println("集合的長度為:"+set.size());
Iterator it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
輸出結(jié)果:
集合的長度:5
Person [id=1, name=小明] //根據(jù)id為1計算的哈希地址
Person [id=5, name=小張] //根據(jù)id為2計算的哈希地址(原p2對象以id為2的哈希地址進行存儲,但是后來id被修改為5了)
Person [id=2, name=小張] //根據(jù)id為2計算的哈希地址(p4對象)
Person [id=3, name=小李] //根據(jù)id為3計算的哈希地址
Person [id=5, name=小張] //根據(jù)id為5計算的哈希地址(修改以后的p2以id為5計算的哈希地址存儲)
HashSet存儲元素的存儲過程:
首先說一下HashSet存儲對象的方式:首先根據(jù)我們重寫的HashCode方法計算出Hash值,根據(jù)Hash值來判斷存入Set中的元素是否重復(fù)和存儲在Set集合中的哈希地址,如果該Hash地址為空,則會直接將該對象存儲到該哈希地址,如果該哈希地址有元素,會根據(jù)equals方法判斷是否為同一個對象,如果結(jié)果返回true,說明兩個對象是同一對象,則不會添加該對象,如果返回的是false,說明元素本身是不同的,則會以鏈表的形式同時存儲到該哈希地址的位置。
總結(jié):說一下上面的執(zhí)行過程,Set集合是根據(jù)我們重寫的HashCode方法中的屬性,來計算Hash值,來判斷存入Set中的元素是否重復(fù)和存儲在Set集合中哈希地址,當(dāng)我們在存儲之后再進行修改決定計算Hash值的屬性時,會導(dǎo)致程序出現(xiàn)意想不到的結(jié)果,我們首先根據(jù)id為2計算出了一個存儲該對象的哈希地址,當(dāng)我們修改了id為5后,再進行刪除操作時,它會根據(jù)id為5計算一個Hash值,去該Hash值對應(yīng)的哈希地址去刪除元素,因為我們之前存儲的哈希地址是根據(jù)id為2計算出來的,所以會導(dǎo)致本應(yīng)刪除的元素刪除不掉,而當(dāng)我們再進行add的時候,我們根據(jù)id為5的Hash值去存儲時發(fā)現(xiàn),id為5的地址并沒有元素,所以存儲成功,雖然和之前id為2時計算Hash值存儲位置的元素屬性值一樣,但是還是會存儲成功的,然而,當(dāng)我們再創(chuàng)建一個id為2的對象進行存儲時,雖然哈希地址相同,但此時之前根據(jù)該哈希地址的對象已經(jīng)改變了(id修改為5了),所以會將新創(chuàng)建的id為2的對象以鏈表的形式同時存儲在該哈希地址的位置,所以當(dāng)我們操作HashSet集合時,不要去修改決定計算Hash值的元素屬性。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
IntelliJ IDEA 2020 安裝和常用配置(推薦)
這篇文章主要介紹了IntelliJ IDEA 2020 安裝和常用配置(推薦),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
java使用ArrayList實現(xiàn)斗地主(無序版)
這篇文章主要為大家詳細(xì)介紹了java使用ArrayList實現(xiàn)斗地主,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-03-03
Java實現(xiàn)數(shù)組轉(zhuǎn)字符串及字符串轉(zhuǎn)數(shù)組的方法分析
這篇文章主要介紹了Java實現(xiàn)數(shù)組轉(zhuǎn)字符串及字符串轉(zhuǎn)數(shù)組的方法,結(jié)合實例形式分析了Java字符串及數(shù)組相關(guān)的分割、遍歷、追加等操作技巧,需要的朋友可以參考下2018-06-06
SpringBoot短鏈接跳轉(zhuǎn)的代碼實現(xiàn)
短鏈跳轉(zhuǎn)是一種通過將長鏈接轉(zhuǎn)換為短鏈接的方式,以便在互聯(lián)網(wǎng)上進行鏈接共享和傳播的技術(shù),短鏈將原始長鏈接通過特定算法轉(zhuǎn)換為較短的鏈接,使得它更容易分享、傳播和展示,本文給大家介紹了SpringBoot短鏈接跳轉(zhuǎn)的代碼實現(xiàn),需要的朋友可以參考下2024-03-03
企業(yè)級Kubernetes管理平臺Wayne功能特性介紹
這篇文章主要為大家介紹了企業(yè)級Kubernetes管理平臺Wayne的功能特性及架構(gòu)設(shè)計,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2022-02-02
SpringData Repository Bean方法定義規(guī)范代碼實例
這篇文章主要介紹了SpringData Repository Bean方法定義規(guī)范代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-08-08

