摘要:注實(shí)際應(yīng)用中,我們一般是用集合來存儲(chǔ)相同的字符串的,不會(huì)用來存。解答雖然我們不能用來存放類型重復(fù)的字符串,但我們可以用來存儲(chǔ)類型重復(fù)的字符串呀。而對(duì)于類型,相同字符串的不同對(duì)象哈希值是不同的。
有一種學(xué)得快的方法,就是不要一次學(xué)太多。1. 前言
今天,我們來探討一個(gè)實(shí)際中不常用但卻比較有意思的問題。它能幫助你理解 “HashSet中的鍵值是唯一的,不可重復(fù)的” 這句話的真正含義,也考驗(yàn)?zāi)銓?duì)問題的思考深度。
注:實(shí)際應(yīng)用中,我們一般是用 ArrayList 集合來存儲(chǔ)相同的字符串的,不會(huì)用 HashSet 來存。
我們平時(shí)都看到或聽說 HashSet 是不能用來存放重復(fù)的字符串的,是真的存放不了嗎?如果面試問你這個(gè)問題,你能給出解決方案嗎?
2. 參考解答先給出參考解答,然后我們?cè)賮矸治鰹槭裁础?
解答:
雖然我們不能用 HashSet 來存放 String 類型重復(fù)的字符串,但我們可以用 HashSet 來存儲(chǔ) StringBuilder 類型重復(fù)的字符串呀。
public class HashSetTest { public static void main(String[] args){ // 用 HashSet 來存放 String 類型的重復(fù)的字符串會(huì)發(fā)生什么? HashSeths1 = new HashSet<>(); String s1 = new String("aaa"); String s2 = new String("aaa"); String s3 = new String("aaa"); hs1.add(s1); hs1.add(s2); hs1.add(s3); System.out.println("hs1:"+hs1); // 重復(fù)的字符串是存不進(jìn)去的 // 用 HashSet 來存放 StringBuilder 類型的重復(fù)的字符串又會(huì)發(fā)生什么? HashSet hs2 = new HashSet<>(); StringBuilder sb1 = new StringBuilder("aaa"); StringBuilder sb2 = new StringBuilder("aaa"); StringBuilder sb3 = new StringBuilder("aaa"); hs2.add(sb1); hs2.add(sb2); hs2.add(sb3); System.out.println("hs2:"+hs2); // 咦,結(jié)果發(fā)現(xiàn)重復(fù)的字符串也能存進(jìn)去了 // 那為什么呢?我們來打印一個(gè)各個(gè)對(duì)象的hashCode看一下 System.out.println("s1的hashCode:"+s1.hashCode()); System.out.println("s2的hashCode:"+s2.hashCode()); System.out.println("s3的hashCode:"+s3.hashCode()); System.out.println("sb1的hashCode:"+sb1.hashCode()); System.out.println("sb2的hashCode:"+sb2.hashCode()); System.out.println("sb3的hashCode:"+sb3.hashCode()); } }
輸出結(jié)果:
hs1:[aaa] hs2:[aaa, aaa, aaa] s1的hashCode:96321 s2的hashCode:96321 s3的hashCode:96321 sb1的hashCode:356573597 sb2的hashCode:1735600054 sb3的hashCode:21685669
從打印結(jié)果來看,我們是不能用 HashSet 來存放 String 類型的重復(fù)字符串的(如hs1),但我們是可以用HashSet來存放 StringBuilder 類型的重復(fù)字符串。
3. 為什么?從打印的 hashCode 來看,String 類型,相同字符串的不同 String 對(duì)象哈希值是一樣的。而對(duì)于 StringBuilder 類型,相同字符串的不同對(duì)象哈希值是不同的。
要知道這個(gè)問題的答案,我們首先得了解 Java 虛擬機(jī)是如何判斷兩個(gè)對(duì)象是否相同的。
那 Java 虛擬機(jī)是如何判斷兩個(gè)對(duì)象是否相同的呢?參考解答:
Java 虛擬機(jī)會(huì)先判斷兩個(gè)對(duì)象的 hashCode 是否相同,如果 hashCode 不同,則說明肯定是兩個(gè)不同的對(duì)象了;如果 hashCode 相同再通過 equals() 方法進(jìn)行進(jìn)一步比較,如果 equals 方法返回 true,則說明兩個(gè)對(duì)象是相同的,如果equals方法返回 false 說明兩個(gè)對(duì)象不同。
具體驗(yàn)證思路如果你感興趣,請(qǐng)查看: JDK 是如何判斷兩個(gè)對(duì)象是否相同的?判斷的流程是什么?
那為什么相同字符串的不同 String 對(duì)象哈希值是一樣的,而且還被虛擬機(jī)判斷為相同的對(duì)象了呢?因?yàn)?String 類復(fù)寫了 Object 類的 hashCode() 和 equals() 方法,并實(shí)現(xiàn)了自己的 hashCode 值生成算法和 equals 的比較規(guī)則,具有相同字符串內(nèi)容的不同 String 對(duì)象在初始化時(shí)生成的 hashCode 值是一樣的,并且 String 類 equals() 方法比較的是兩個(gè)字符串的內(nèi)容,而不是內(nèi)存地址值,這兩個(gè)條件同時(shí)成立, 這就使 Java 虛擬機(jī)把具有相同內(nèi)容的不同 String 對(duì)象判斷為相同的對(duì)象了,就不會(huì)存入 HashSet 集合中。
而 StringBuilder 為什么就可以呢?它相同內(nèi)容的不同對(duì)象的哈希值值為什么是不同的?查看 StringBuilder 類的源碼你會(huì)發(fā)現(xiàn),因?yàn)?StringBuilder 并沒有復(fù)寫 Object 類的 hashCode() 方法和 equals() 方法,StringBuilder 用的是父類 Object 類的 hashCode 生成算法,也就是用 native 層的 hashCode 生成算法,很大概率產(chǎn)生的哈希值是不一樣的,即使產(chǎn)生了一樣的哈希值,Object 類的 equals() 方法比較的是兩個(gè)對(duì)象的內(nèi)存地址,而不是兩個(gè)對(duì)象的內(nèi)容,這就使 Java 虛擬機(jī)把具有相同內(nèi)容的 StringBuilder 對(duì)象判斷為不同的對(duì)象,就可以存入 HashSet 集合中了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/73408.html
摘要:集合中成員很豐富,常用的集合有,,等。實(shí)現(xiàn)接口的集合主要有。集合中不能包含重復(fù)的元素,每個(gè)元素必須是唯一的。而以作為實(shí)現(xiàn)的構(gòu)造函數(shù)的訪問權(quán)限是默認(rèn)訪問權(quán)限,即包內(nèi)訪問權(quán)限。與接口不同,它是由一系列鍵值對(duì)組成的集合,提供了到的映射。 原文地址 Java集合 Java集合框架:是一種工具類,就像是一個(gè)容器可以存儲(chǔ)任意數(shù)量的具有共同屬性的對(duì)象。 Java集合中成員很豐富,常用的集合有Arra...
摘要:如果你知道用集合,就用。在集合中常見的數(shù)據(jù)結(jié)構(gòu)底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,查詢快,增刪慢底層數(shù)據(jù)結(jié)構(gòu)是鏈表,查詢慢,增刪快底層數(shù)據(jù)結(jié)構(gòu)是哈希表。依賴兩個(gè)方法和底層數(shù)據(jù)結(jié)構(gòu)是二叉樹。 第三階段 JAVA常見對(duì)象的學(xué)習(xí) 集合框架——Set接口 showImg(https://segmentfault.com/img/remote/1460000019683927?w=700&h=280); Lis...
摘要:并把最終的隨機(jī)數(shù)輸出到控制臺(tái)。方法,在集合中如何存儲(chǔ)元素取決于方法的返回值返回,集合中只有一個(gè)元素。創(chuàng)建集合對(duì)象,傳入比較器。 1_HashSet存儲(chǔ)字符串并遍歷 A:Set集合概述及特點(diǎn) 通過API查看即可 B:案例演示 HashSet存儲(chǔ)字符串并遍歷 import java.util.HashSet; public class Demo1_HashSet { p...
摘要:接口的特點(diǎn)接口的特點(diǎn)它是一個(gè)元素存取有序的集合。導(dǎo)致迭代器并不知道集合中的變化,容易引發(fā)數(shù)據(jù)的不確定性。枚舉已被迭代器替代。集合取出元素的方式可以采用迭代器增強(qiáng)。 01List接口的特點(diǎn) A:List接口的特點(diǎn): ?a:它是一個(gè)元素存取有序的集合。 例如,存元素的順序是11、22、33。那么集合中,元素的存儲(chǔ)就是按照11、22、33的順序完成的)。 ?b:它是一個(gè)帶有索引的...
閱讀 1307·2021-11-16 11:44
閱讀 3774·2021-10-09 10:01
閱讀 1769·2021-09-24 10:31
閱讀 3858·2021-09-04 16:41
閱讀 2528·2021-08-09 13:45
閱讀 1226·2019-08-30 14:08
閱讀 1791·2019-08-29 18:32
閱讀 1652·2019-08-26 12:12