1、Set接口
-
特點(diǎn):
無(wú)序的:不保證元素的插入次序。
唯一:Set中存放的是對(duì)象的引用,所以相同的對(duì)象是沒(méi)法添加到集合中,即集合中不允許有相同的元素對(duì)象。主要先根據(jù)hashcode值,如果相同再看是否重寫了equals方法。
-
注意:
雖然Set中元素沒(méi)有順序,但是元素在set中的位置是由該元素的HashCode決定的,其具體位置其實(shí)是固定的。
2、常用實(shí)現(xiàn)類:
HashSet :
1、它不允許出現(xiàn)重復(fù)元素;不保證集合中元素的順序
2、 允許包含值為null的元素,但最多只能有一個(gè)null元素。
3、 HashSet按Hash算法來(lái)存儲(chǔ)集合的元素,因此具有很好的存取和查找性能。
-
HashSet使用和理解中容易出現(xiàn)的誤區(qū):
a.HashSet中存放null值
HashSet中是允許存入null值的,但是在HashSet中僅僅能夠存入一個(gè)null值。b.HashSet中存儲(chǔ)元素的位置是固定的
HashSet中存儲(chǔ)的元素的是無(wú)序的,這個(gè)沒(méi)什么好說(shuō)的,但是由于HashSet底層是基于Hash算法實(shí)現(xiàn)的,使用了hashcode,所以HashSet中相應(yīng)的元素的位置是固定的。
TreeSet :
可以實(shí)現(xiàn)排序等功能的集合,它在講對(duì)象元素添加到集合中時(shí)會(huì)自動(dòng)按照某種比較規(guī)則將其插入到有序的對(duì)象序列中,并保證該集合元素組成按照“升序”排列。
TreeSet是一個(gè)有序集合,其底層是基于TreeMap實(shí)現(xiàn)的,非線程安全。TreeSet可以確保集合元素處于排序狀態(tài)。TreeSet支持兩種排序方式,自然排序和定制排序,其中自然排序?yàn)槟J(rèn)的排序方式。當(dāng)我們構(gòu)造TreeSet時(shí),若使用不帶參數(shù)的構(gòu)造函數(shù),則TreeSet的使用自然比較器;若用戶需要使用自定義的比較器,則需要使用帶比較器的參數(shù)。
- 注意:
TreeSet集合不是通過(guò)hashcode和equals函數(shù)來(lái)比較元素的,而是通過(guò)實(shí)現(xiàn)Comparable接口并重寫compareTo()方法或者Comparator接口的compare()來(lái)判斷元素是否相等
- 小結(jié):
a) 在對(duì)大量信息進(jìn)行檢索(不知道下標(biāo),比如contains)的時(shí)候,TreeSet比ArrayList更有效率。
b) TreeSet是用樹形結(jié)構(gòu)來(lái)存儲(chǔ)信息的,每個(gè)節(jié)點(diǎn)都會(huì)保存一下指針對(duì)象,分別指向父節(jié)點(diǎn),左分支,右分支,相比較而言,ArrayList就是一個(gè)含有元素的簡(jiǎn)單數(shù)組了,正因?yàn)槿绱?,它占的?nèi)存也要比ArrayList多一些。
c) 想TreeSet插入元素也比ArrayList要快一些,因?yàn)楫?dāng)元素插入到ArrayList的任意位置時(shí),平均每次要移動(dòng)一半的列表(普遍的都是,set查詢慢,插入快,list查詢快,插入慢)。
3、示例代碼
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class TestHashSet {
public static void main(String[] args) {
// HashSet的基本用法
// Set集合特點(diǎn):
// 1、存儲(chǔ)的元素是無(wú)序(不是添加的順序),且唯一(不可重復(fù))
// 創(chuàng)建Set集合對(duì)象
Set<String> carSet = new HashSet<>();
// 添加元素:add(Object obj)
System.out.println("------------------- 無(wú)序 -------------------");
carSet.add("Audi");
carSet.add("Benz");
carSet.add("Bmw");
carSet.add("Volvo");
System.out.println("carSet集合元素:" + carSet);
System.out.println("------------------- 唯一 -------------------");
carSet.add("Volvo");
System.out.println("carSet集合元素:" + carSet);
// 擴(kuò)展:能不能存放null元素?可以,數(shù)量只有一個(gè)
System.out.println("------------------- null -------------------");
carSet.add(null);
carSet.add("Byd");
carSet.add(null);
System.out.println("carSet字符串集合元素:" + carSet);
// 獲取元素:get(index),沒(méi)有此方法,set集合是無(wú)序,元素沒(méi)有下標(biāo),沒(méi)有根據(jù)下標(biāo)獲取元素的方法
// carSet.get(0); // 編譯不通過(guò),沒(méi)有此方法
// 獲取元素個(gè)數(shù):size() , 返回集合中元素個(gè)數(shù)
System.out.println("------------------- size -------------------");
System.out.println("carSet字符串集合元素個(gè)數(shù):" + carSet.size());
// 判斷是否包含某個(gè)元素:contains(Object obj),如果包含指定元素,返回true,否則返回false
System.out.println("------------------- contains -------------------");
System.out.println("carSet字符串集合是否包含Bmw?:" + carSet.contains("Bmw"));
// 其它的集合操作方法,比如判斷非空,清空等,不一一介紹,課后自行測(cè)試
// 遍歷集合中的元素:
// 方式1:使用迭代器
System.out.println("------------------- 迭代器遍歷 -------------------");
Iterator<String> carIterator = carSet.iterator();
while (carIterator.hasNext()) {
System.out.println("carSet中的元素:" + carIterator.next());
}
// 方式2:增強(qiáng)for循環(huán),普通for無(wú)法實(shí)現(xiàn)
System.out.println("------------------- 增強(qiáng)for遍歷 -------------------");
for (String carStr : carSet) {
System.out.println("carSet中的元素:" + carStr);
}
// 探討:Set集合中,存儲(chǔ)的元素是唯一的,重復(fù)的元素如何保證唯一?是覆蓋重復(fù)元素還是加不進(jìn)去?
// 不是覆蓋,先判斷元素的hashCode值,如果相同,再判斷equals是否相同,如果相同,不添加
// 創(chuàng)建SetUnique對(duì)象1
SetUnique setUnique1 = new SetUnique();
setUnique1.setSetScore(100);
// 創(chuàng)建SetUnique對(duì)象2
SetUnique setUnique2 = new SetUnique();
setUnique2.setSetScore(150);
System.out.println("------------------- -------------------");
System.out.println("== 判斷 setUnique1和setUnique2是否是同一個(gè)對(duì)象?" + (setUnique1 == setUnique2));
System.out.println("equals 判斷 setUnique1和setUnique2是否是同一個(gè)對(duì)象?" + (setUnique1.equals(setUnique2)));
// 創(chuàng)建set集合,添加元素
Set<SetUnique> setUniques = new HashSet<>();
setUniques.add(setUnique1);
setUniques.add(setUnique2);
System.out.println("setUniques中元素:" + setUniques);
}
}
/**
* Set唯一特性測(cè)試類
*
* @author xiayimiaoyijiuyonggan
*
*/
public class SetUnique {
private int setScore;
public int getSetScore() {
return setScore;
}
public void setSetScore(int setScore) {
this.setScore = setScore;
}
@Override
public int hashCode() {
// 重新hashCode
// 場(chǎng)景1:setScore值作為hashCode值,
// return this.setScore;
// 場(chǎng)景2:自定義一個(gè)邏輯,確保不同的setScore,返回相同的hashCode
return this.setScore / 100;
}
@Override
public boolean equals(Object obj) {
// 重寫equals方法
// TODO 參數(shù)非空,類型判斷(instanceOf)不做了
// 場(chǎng)景1:默認(rèn)不管setScore是否相同,默認(rèn)都是同一個(gè)對(duì)象,hashCode值不同,即便equals相同也是不同對(duì)象
return true;
// 場(chǎng)景2:自定義一個(gè)邏輯,根據(jù)setScore判斷是否是同一個(gè)對(duì)象,如果setScore相同,就是同一個(gè)對(duì)象,不同就不是同一個(gè)對(duì)象
// hashCode值相同,會(huì)判斷equals是否相同,如果相同就是同一個(gè)對(duì)象,如果不同就不是同一個(gè)對(duì)象
/*
* SetUnique setUnique = (SetUnique) obj; // 判斷setScore值是否相同 if
* (this.setScore != setUnique.getSetScore()) { // 不是同一個(gè)對(duì)象 return false;
* }
*
* // 同一個(gè)對(duì)象 return true;
*/
}
@Override
public String toString() {
return "SetUnique [setScore=" + setScore + "]";
}
}