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