java中的HashSet與 == 和 equals的區(qū)別示例解析
什么是HashSet
在 Java 中,HashSet 是一個(gè)基于哈希表實(shí)現(xiàn)的集合類,它實(shí)現(xiàn)了 Set 接口
HashSet 的主要特點(diǎn)是:1,2
HashSet 的主要特點(diǎn)是
1,集合中的數(shù)據(jù)不能夠重復(fù)
2,存儲(chǔ)的數(shù)據(jù)是無(wú)序的(元素的存儲(chǔ)順序與插入順序無(wú)關(guān))
3,允許 null 值: 可以存儲(chǔ)一個(gè) null 元素(感覺(jué)這個(gè)不算)
HashSet 的常用方法
boolean add(e)向集合中添加元素。如果元素已存在,則返回 false。
boolean remove(Object o)從集合中移除指定元素。如果元素存在并成功移除,則返回 true。
boolean contains(Object o)檢查集合中是否包含指定元素。如果存在,則返回 true。
int size() 返回集合中元素的數(shù)量。
boolean isEmpty()檢查集合是否為空。如果為空,則返回 true。
void clear()清空集合中的所有元素。
Iterator iterator() 返回一個(gè)迭代器,用于遍歷集合中的元素。
Object[] toArray() 將集合轉(zhuǎn)換為數(shù)組。
hasSet存儲(chǔ)為啥是無(wú)序的
hasSet 存儲(chǔ)為啥數(shù)據(jù)不能夠重復(fù)
hash存儲(chǔ)是冪等性算法
也就是說(shuō):你給我一個(gè)A,計(jì)算出來(lái)的是2。
下次你再給一個(gè)A,計(jì)算出來(lái)的仍然是2。
這樣的話,就會(huì)造成一個(gè)問(wèn)題。
這個(gè)2要不要存儲(chǔ)呢?
hasSet會(huì)丟棄第2個(gè)相同的值,因此存儲(chǔ)的數(shù)據(jù)是不能夠重復(fù)的。
存儲(chǔ)數(shù)據(jù)是無(wú)序的
package part; // HashSet在util這個(gè)包中,需要我們引入 import java.util.HashSet; public class Java01 { public static void main(String[] args) { HashSet setObject = new HashSet(); setObject.add("張三"); setObject.add("李四"); setObject.add("趙6"); // 輸出的來(lái)是: [趙6, 李四, 張三] 說(shuō)明存儲(chǔ)數(shù)據(jù)是無(wú)序的 System.out.println(setObject); } }
存儲(chǔ)的數(shù)據(jù)是不會(huì)重復(fù)的
public class Java01 { public static void main(String[] args) { HashSet setObject = new HashSet(); setObject.add("張三"); setObject.add("李四"); setObject.add("張三"); // 輸出的來(lái)是: System.out.println(setObject); } }
HashSet如何修改數(shù)據(jù)
HashSet無(wú)法直接修改數(shù)據(jù)。
我們需要先把某一條要修改的數(shù)據(jù)刪除掉。在新增我們想要的數(shù)據(jù)
package part; // HashSet在util這個(gè)包中,需要我們引入 import java.util.HashSet; public class Java01 { public static void main(String[] args) { HashSet setObject = new HashSet(); setObject.add("張三"); setObject.add("李四"); // 把張三更改為張3,我們先刪除然后再新增 setObject.remove("張三"); setObject.add("張3"); // 輸出: [李四, 張3] System.out.println(setObject); } }
增強(qiáng) for循環(huán)(也稱為 for-each 循環(huán)) 來(lái)遍歷數(shù)據(jù)
package part; // HashSet在util這個(gè)包中,需要我們引入 import java.util.HashSet; public class Java01 { public static void main(String[] args) { HashSet setObject = new HashSet(); setObject.add("張三"); setObject.add("李四"); setObject.add("王五"); // 我們通過(guò)特殊for循環(huán)來(lái)遍歷數(shù)據(jù) for (Object o : setObject) { System.out.println(o); } } }
增強(qiáng) for循環(huán)的語(yǔ)法
for (元素類型 變量名 : 數(shù)組或集合) { // 循環(huán)體 // ps: 變量名是循環(huán)中的每一項(xiàng) }
HashSet.add新增元素(如果元素已存在,則返回 false)
package part; // HashSet在util這個(gè)包中,需要我們引入 import java.util.HashSet; public class Java01 { public static void main(String[] args) { HashSet setObject = new HashSet(); setObject.add("張三"); setObject.add("李四"); setObject.add("王五"); // 輸出的是 [李四, 張三, 王五] System.out.println(setObject); } }
HashSet.addAll 將一個(gè)集合中的所有元素添加到另一個(gè)集合中
package part; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; public class Java01 { public static void main(String[] args) { HashSet setObject = new HashSet(); ArrayList<Integer> listObject = new ArrayList(); listObject.add(1); listObject.add(2); LinkedList linkedListObject = new LinkedList(); linkedListObject.add("張三"); // 添加一個(gè)ArrayList集合對(duì)象 setObject.addAll(listObject); // 添加一個(gè)LinkedList集合對(duì)象 setObject.addAll(linkedListObject); // 輸出的是: [1, 2, 張三] System.out.println("setObject:" + setObject); } }
HashSet.toArray 將HashSet轉(zhuǎn)化為數(shù)組
public class Java01 { public static void main(String[] args) { HashSet setObject = new HashSet(); setObject.add("張三"); setObject.add("李四"); setObject.add("王五"); // 將 HashSet 轉(zhuǎn)換為數(shù)組 Object obj = setObject.toArray(); System.out.println(obj); } }
HashSet.size() 獲取HashSet 的長(zhǎng)度
public class Java01 { public static void main(String[] args) { HashSet setObject = new HashSet(); setObject.add("張三"); setObject.add("李四"); setObject.add("王五"); // 獲取HashSet 的長(zhǎng)度 int len = setObject.size(); System.out.println(len); } }
HashSet.clone 克隆
package part; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; public class Java01 { public static void main(String[] args) { HashSet setObject = new HashSet(); setObject.add("張三"); setObject.add("李四"); setObject.add("王五"); // 克隆HashSet,相當(dāng)于復(fù)制了一份。但是我們需要使用Object來(lái)聲明 Object newSet = setObject.clone(); } }
克隆 HashSet 可以不用Object來(lái)聲明嗎?
克隆 HashSet 可以不用 Object 來(lái)聲明嗎? 可以的。
那為啥克隆需要使用 Object來(lái)聲明呢?
因?yàn)椋篶lone() 方法的返回類型是 Object。所以我們需要使用Object來(lái)聲明。
我們可以使用強(qiáng)制轉(zhuǎn)化來(lái)處理就行
public class Java01 { public static void main(String[] args) { HashSet setObject = new HashSet(); setObject.add("張三"); setObject.add("李四"); setObject.add("王五"); // 克隆HashSet,相當(dāng)于復(fù)制了一份。我們可以使用強(qiáng)制轉(zhuǎn)化來(lái)解決這個(gè)問(wèn)題的 HashSet newSet =(HashSet) setObject.clone(); } }
HashSet.remove(被移除的對(duì)象)
要從 HashSet 中移除的對(duì)象。如果 HashSet 包含該對(duì)象,則會(huì)被移除。
返回值是一個(gè)布爾值
如果 HashSet 中包含指定的對(duì)象并且成功移除,則返回 true。
如果 HashSet 中不包含該對(duì)象,則返回 false。
public class Java01 { public static void main(String[] args) { HashSet setObject = new HashSet(); setObject.add("張三"); setObject.add("李四"); setObject.add("王五"); // 移除李四 Boolean delStatus = setObject.remove("李四"); // 輸出的是true System.out.println(delStatus); } }
ArrayList.remove根據(jù)傳參不同,返回的類型不同
ArrayList arrList = new ArrayList(); arrList.add("嘿嘿01"); // 傳參的是數(shù)字,返回的是被刪除的數(shù)據(jù) Object oldValue = arrList.remove(0);
public class Java01 { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("A"); // 傳參字符串,返回來(lái)的是布爾 Boolean flag = list.remove("A"); System.out.println(flag); } }
HashSet存儲(chǔ)了相同的數(shù)據(jù)
package part; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; public class Java01 { public static void main(String[] args) { HashSet setList = new HashSet(); User u1 = new User(); User u2 = new User(); u1.id = "2025_01_30"; u1.name = "張三"; u2.id = "2025_01_30"; u2.name = "張三"; setList.add(u1); setList.add(u2); // 大家認(rèn)為會(huì)輸出什么呢? // 輸出的 [User [id=2025_01_30, name=張三], User [id=2025_01_30, name=張三]] System.out.println(setList); } } class User{ String id; String name; // ctrl + o 就可以啦 現(xiàn)在我重寫了 toString @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } }
不是說(shuō):HashSet中的數(shù)據(jù)不能重復(fù)嗎?
為啥會(huì)重復(fù)呢?
因?yàn)?這2個(gè)對(duì)象在內(nèi)存中是不同的地址哈~。
所以HashSet會(huì)認(rèn)為是不同的值。
內(nèi)存中是不同的地址我們一般認(rèn)為是 hashCode不同(這種說(shuō)法不準(zhǔn)確,但是方便我們理解)
ps: hashCode類似與內(nèi)存中的地址
解釋為啥存儲(chǔ)了相同的數(shù)據(jù)
package part; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; public class Java01 { public static void main(String[] args) { HashSet setList = new HashSet(); User u1 = new User(); User u2 = new User(); u1.id = "2025_01_30"; u1.name = "張三"; u2.id = "2025_01_30"; u2.name = "張三"; setList.add(u1); setList.add(u2); // hashCode 我們可以理解為內(nèi)存中的地址(這種說(shuō)法不準(zhǔn)確,但是方便我們理解) System.out.println(u1.hashCode()); // 685325104 System.out.println(u2.hashCode()); // 460141958 // 我們發(fā)現(xiàn)這2個(gè)地址不同,就會(huì)認(rèn)為是2個(gè)不同的對(duì)象,就會(huì)出現(xiàn)相同的數(shù)據(jù) } } class User{ String id; String name; // ctrl + o 就可以啦 @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } }
如何如果讓一個(gè)對(duì)象的id和name相同,就讓它識(shí)別為是同一個(gè)數(shù)據(jù)
如果讓一個(gè)對(duì)象的id和name相同,就讓它識(shí)別為是同一個(gè)數(shù)據(jù)呢?
是可以的。我們需要重寫2個(gè)方法;hashCode 和 equals
因?yàn)? HashSet是在存儲(chǔ)數(shù)據(jù)的時(shí)候,就是通過(guò)hashCode來(lái)操作的。
我們給定一個(gè)值(字符串), 通過(guò)操作得到存儲(chǔ)到哪一個(gè)位置。
當(dāng)然不同的值可能得到的存儲(chǔ)位置是一樣的。
如果出現(xiàn)這樣的情況,他會(huì)去比較他們的equals。
如果相等,會(huì)把這個(gè)數(shù)據(jù)(后面這個(gè)新增的數(shù)據(jù))丟棄,什么都不做。
如果不相等,這個(gè)時(shí)候他會(huì)使用鏈表它裝在一起哈。
我們也可以從這里得出結(jié)論:HashSet的底層是:數(shù)組+鏈表的結(jié)構(gòu)來(lái)進(jìn)行存儲(chǔ)數(shù)據(jù)的
重寫hashCode 和 equals
package part; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; public class Java01 { public static void main(String[] args) { HashSet setList = new HashSet(); User u1 = new User(); User u2 = new User(); u1.id = 2025; u1.name = "張三"; u2.id = 2025; u2.name = "張三"; setList.add(u1); setList.add(u2); // [User [id=2025, name=張三]] 現(xiàn)在數(shù)據(jù)就不會(huì)重復(fù)了 System.out.println(setList); } } class User{ int id; String name; // 重寫方法的快捷鍵 ctrl+o @Override // 類似與我們的內(nèi)存地址,我們使用id來(lái)判斷 public int hashCode() { return id; } @Override // 判斷2個(gè)對(duì)象的屬性是否完全相同 public boolean equals(Object obj) { if(obj instanceof User) { //因?yàn)檫@個(gè)對(duì)象是User類型的,我們可以使用強(qiáng)制轉(zhuǎn)換 User u = (User)obj; //判斷對(duì)象的屬性是否相同,這里為啥使用equals,等會(huì)回說(shuō)一下 if(u.id==this.id && u.name.equals(this.name)) { return true; }else{ return false; } }else{ // 如果不是,直接返回false return false; } } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } }
HashSet的底層是:數(shù)組+鏈表的結(jié)構(gòu)來(lái)進(jìn)行存儲(chǔ)數(shù)據(jù)的
== 和 equals的區(qū)別
1,當(dāng)使用 == 比較基本數(shù)據(jù)類型,它比較的是兩個(gè)變量的值是否相等。
2,當(dāng)使用 == 比較引用數(shù)據(jù)類型(如對(duì)象)時(shí),它比較的是對(duì)象的內(nèi)存地址是否相等,即它們是否引用同一內(nèi)存地址。
3,equals是Object類中的一個(gè)方法,用于比較同一類的兩個(gè)對(duì)象的內(nèi)容是否相等。
equals的比較邏輯
equals方法首先檢查兩個(gè)對(duì)象是否為同一類的實(shí)例(即類是否相等)。
如果不屬于同一類,則對(duì)象肯定不相等。
如果類相等,equals方法將逐一比較兩個(gè)對(duì)象的字段或?qū)傩?,以確定它們是否相等。
適用場(chǎng)景:
對(duì)于基本數(shù)據(jù)類型,== 用于比較值是否相
對(duì)于引用數(shù)據(jù)類型:如對(duì)象,通常使用 equals 方法進(jìn)行內(nèi)容比較。
方法重寫:
== 的行為固定,不可更改。
equals 方法可以在自定義類中重寫,以實(shí)現(xiàn)特定的比較邏輯。
到此這篇關(guān)于java中的HashSet與 == 和 equals的區(qū)別的文章就介紹到這了,更多相關(guān)java HashSet與 == 和 equals區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java LinkedHashSet集合的底層原理和TreeSet集合
- Java中HashMap和HashSet的高效使用技巧分享
- Java中的Set接口實(shí)現(xiàn)類HashSet和LinkedHashSet詳解
- Java集合ArrayList、LinkedList、HashMap、HashSet最大容量
- Java中HashSet、LinkedHashSet和TreeSet區(qū)別詳解
- java的==運(yùn)算符和equals操作詳解
- Java中==和equals()的區(qū)別總結(jié)
- java兩個(gè)integer數(shù)據(jù)判斷相等用==還是equals
- 詳解Java中==和equals()的區(qū)別
- 淺談java字符串比較到底應(yīng)該用==還是equals
相關(guān)文章
SpringBoot如何通過(guò)@Profile注解配置多環(huán)境
在Spring中,可以使用配置文件的方式來(lái)指定不同環(huán)境下所需要的配置信息,本文給大家介紹SpringBoot如何通過(guò)@Profile注解配置多環(huán)境,感興趣的朋友跟隨小編一起看看吧2023-06-06Intellij IDEA 添加jar包的三種方式(小結(jié))
這篇文章主要介紹了Intellij IDEA 添加jar包的三種方式(小結(jié)),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08SpringBoot集成Swagger2構(gòu)建在線API文檔的代碼詳解
這篇文章主要介紹了SpringBoot集成Swagger2構(gòu)建在線API文檔,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12Java虛擬機(jī)JVM性能優(yōu)化(一):JVM知識(shí)總結(jié)
這篇文章主要介紹了Java虛擬機(jī)JVM性能優(yōu)化(一):JVM知識(shí)總結(jié),本文是系列文章的第一篇,后續(xù)篇章請(qǐng)繼續(xù)關(guān)注腳本之家,需要的朋友可以參考下2014-09-09使用spring的restTemplate注意點(diǎn)
這篇文章主要介紹了使用spring的restTemplate注意點(diǎn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10java8中的List<String>轉(zhuǎn)List<Integer>的實(shí)例代碼
這篇文章主要介紹了java8中的List<String>轉(zhuǎn)List<Integer>,轉(zhuǎn)換list列表String到列表Intger,java8提供了stream很好的進(jìn)行操作,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07Java main方法String[]args原理實(shí)例解析
這篇文章主要介紹了Java main方法String[]args原理實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06基于Java8實(shí)現(xiàn)提高Excel讀寫效率
這篇文章主要介紹了基于Java8實(shí)現(xiàn)提高Excel讀寫效率,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11