淺談String類型等值比較引起的“==”、“equals()”和“hashCode”思考
關(guān)于String類型的等值比較和內(nèi)容比較,是學習java甚至任何編程語言所共同的常見問題,理解String類型的等值比較和內(nèi)容比較也是面試經(jīng)常問到的問題。
String類型的等值比較和內(nèi)容比較
字符串等值比較
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
首先,如上述String的源碼可以知道的是,java中等值比較,就是“==”比較,比較的是地址。字符串本質(zhì)上是final修飾的字符數(shù)組,也就是說,當創(chuàng)建字符串對象時,字符串的引用是常量,但它每一個對象的值可以改變。
字符串內(nèi)容比較
如上述String的源碼可以知道的是,字符串的內(nèi)容比較就是所謂的字符串的equals()方法,比較的是兩個字符串對象儲存的值,也就是內(nèi)容是否相等,所謂內(nèi)容相同,就是字符串每一個位置的字符相同。這里值得注意的是String重寫了Object的equals()方法(Object的==與equals()是一樣的)
地址分配圖示
很明顯str1和str2的地址相同,他們與str3的地址不相同,但是str3通過方法intern(),可以強制入池,和str1和str2的地址相同。
結(jié)論
字符串:默認為常量------------進常量池
String val = “xxx”;---------------------------默認入池
String val = new String(“xxx”);--------------------------默認入堆,但可以通過intern()強制入池(堆里的對象還在)
上面只是簡單的介紹string類的對象等值比較,下面我們來深刻的了解下java 對象的等值判斷。
對象相等判斷
== 和 equals 的區(qū)別是什么
== : 它的作用是判斷兩個對象的地址是不是相等。即,判斷兩個對象是不是同一個對象。(基本數(shù)據(jù)類型 == 比較的是值,引用數(shù)據(jù)類型 == 比較的是內(nèi)存地址)
equals() : 它的作用也是判斷兩個對象是否相等。但它一般有兩種使用情況:
情況1:類沒有覆蓋 equals() 方法。則通過 equals() 比較該類的兩個對象時,等價于通過“==”比較這兩個對象。
情況2:類覆蓋了 equals() 方法。一般,我們都覆蓋 equals() 方法來兩個對象的內(nèi)容相等;若它們的內(nèi)容相等,則返回 true (即,認為這兩個對象相等)。
舉個例子:
public class test1 { public static void main(String[] args) { String a = new String("ab"); // a 為一個引用 String b = new String("ab"); // b為另一個引用,對象的內(nèi)容一樣 String aa = "ab"; // 放在常量池中 String bb = "ab"; // 從常量池中查找 if (aa == bb) // true System.out.println("aa==bb"); if (a == b) // false,非同一對象 System.out.println("a==b"); if (a.equals(b)) // true System.out.println("aEQb"); if (42 == 42.0) { // true System.out.println("true"); } } }
說明:
String中的equals方法是被重寫過的,因為object的equals方法是比較的對象的內(nèi)存地址,而String的equals方法比較的是對象的值。
當創(chuàng)建String類型的對象時,虛擬機會在常量池中查找有沒有已經(jīng)存在的值和要創(chuàng)建的值相同的對象,如果有就把它賦給當前引用。如果沒有就在常量池中重新創(chuàng)建一個String對象。
hashCode 與 equals (重要)
HashSet如何檢查重復(fù)
兩個對象的 hashCode() 相同,則 equals() 也一定為 true,對嗎?
hashCode和equals方法的關(guān)系
面試官可能會問你:“你重寫過 hashcode 和 equals 么,為什么重寫equals時必須重寫hashCode方法?”
hashCode()介紹
hashCode() 的作用是獲取哈希碼,也稱為散列碼;它實際上是返回一個int整數(shù)。這個哈希碼的作用是確定該對象在哈希表中的索引位置。hashCode() 定義在JDK的Object.java中,這就意味著Java中的任何類都包含有hashCode()函數(shù)。
散列表存儲的是鍵值對(key-value),它的特點是:能根據(jù)“鍵”快速的檢索出對應(yīng)的“值”。這其中就利用到了散列碼!(可以快速找到所需要的對象)
為什么要有 hashCode
我們以“HashSet 如何檢查重復(fù)”為例子來說明為什么要有 hashCode:
當你把對象加入 HashSet 時,HashSet 會先計算對象的 hashcode 值來判斷對象加入的位置,同時也會與其他已經(jīng)加入的對象的 hashcode 值作比較,如果沒有相符的hashcode,HashSet會假設(shè)對象沒有重復(fù)出現(xiàn)。但是如果發(fā)現(xiàn)有相同 hashcode 值的對象,這時會調(diào)用 equals()方法來檢查 hashcode 相等的對象是否真的相同。如果兩者相同,HashSet 就不會讓其加入操作成功。如果不同的話,就會重新散列到其他位置。這樣我們就大大減少了 equals 的次數(shù),相應(yīng)就大大提高了執(zhí)行速度。
hashCode()與equals()的相關(guān)規(guī)定
如果兩個對象相等,則hashcode一定也是相同的
兩個對象相等,對兩個對象分別調(diào)用equals方法都返回true
兩個對象有相同的hashcode值,它們也不一定是相等的
因此,equals 方法被覆蓋過,則 hashCode 方法也必須被覆蓋
hashCode() 的默認行為是對堆上的對象產(chǎn)生獨特值。如果沒有重寫 hashCode(),則該 class 的兩個對象無論如何都不會相等(即使這兩個對象指向相同的數(shù)據(jù))
對象的相等與指向他們的引用相等,兩者有什么不同?
對象的相等 比的是內(nèi)存中存放的內(nèi)容是否相等而 引用相等 比較的是他們指向的內(nèi)存地址是否相等。
以上這篇淺談String類型等值比較引起的“==”、“equals()”和“hashCode”思考就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決Hibernate4執(zhí)行save()或update()無效問題的方法
這篇文章主要為大家詳細介紹了解決Hibernate4執(zhí)行save()或update()無效問題的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-06-06Java Metrics系統(tǒng)性能監(jiān)控工具的使用詳解
Metrics是一個Java庫,可以對系統(tǒng)進行監(jiān)控,統(tǒng)計一些系統(tǒng)的性能指標。本文就來和大家詳細聊聊這個工具的具體使用,希望對大家有所幫助2022-11-11IDEA快速搭建Java開發(fā)環(huán)境的教程圖解
這篇文章主要介紹了IDEA如何快速搭建Java開發(fā)環(huán)境,本文通過圖文并茂的形式給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-11-11Java批量插入數(shù)據(jù)的代碼實現(xiàn)
日常工作或者學習中,可能會遇到批量插入數(shù)據(jù)的需求,一般情況下數(shù)據(jù)量少的時候,我們會直接調(diào)用批量接口插入數(shù)據(jù)即可,當數(shù)據(jù)量特別大時,我們就會用到分批插入數(shù)據(jù),所以本文給大家介紹了Java批量插入數(shù)據(jù)的代碼實現(xiàn),需要的朋友可以參考下2024-01-01springboot實現(xiàn)maven多模塊和打包部署
本文主要介紹了springboot實現(xiàn)maven多模塊和打包部署,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-04-04