一直對Java中的“==”和equals的用法一知半解,在實(shí)際使用中又因?yàn)镃haracter、String等分裝類且伴隨toString和String.valueOf等方法的使用后則更加傻傻分不清楚,需要不斷調(diào)試才能完全搞定,因此痛定思痛,收集了一串資料終于徹底搞懂后,寫以此文,便于自身回顧,同時(shí)以饗讀者。
個(gè)人認(rèn)為《淺談Java中的equals和“==”》 這篇文章講的比較好,本文中的一些示例代碼和關(guān)鍵知識(shí)點(diǎn)也引用于該文章。
要理解關(guān)系操作符“==”和equals的區(qū)別首先要搞清楚數(shù)據(jù)變量類型,JAVA中存在基本數(shù)據(jù)類型變量和非基本數(shù)據(jù)類型變量(專業(yè)點(diǎn)的叫法是對象的引用變量),Java中有8種基本數(shù)據(jù)類型:
浮點(diǎn)型:float(4 byte), double(8 byte)
整型:byte(1 byte), short(2 byte), int(4 byte) , long(8 byte)
字符型: char(2 byte)
布爾型: boolean
需要指出的是這8種基本數(shù)據(jù)類型的變量直接存放在棧中,變量直接存儲(chǔ)的是“值”本身,而不是“地址”。因此在用關(guān)系操作符“==”來進(jìn)行比較時(shí),比較的就是 “值” (這樣設(shè)計(jì)的原因是棧有一個(gè)很重要的特性,存取速度比堆要快,存在棧中的數(shù)據(jù)可以共享,說白了就是為了提升性能)。引用類型的變量存儲(chǔ)的并不是對象的 “值”本身,而是于其關(guān)聯(lián)的對象在內(nèi)存中的地址(如圖 1)。
看如下代碼:
public class Test1 {
public static void main(String[] args) {
int n=3;
int m=3;
System.out.println(n==m); //true
String str = new String("abc");
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1==str2); //false
str1 = str;
str2 = str;
System.out.println(str1==str2); // true
}
由于m和n中直接存儲(chǔ)的是值3,因此比較m==n時(shí),等價(jià)于比較3==3?顯然是相等的,返回true。而比較引用類型變量str1==str2時(shí),等價(jià)于比較對象的地址值0x001==0x333?顯然是不相等的,返回false,口語化的表示方式為str1和str2指向的是兩個(gè)不同的對象。而將str引用對象的地址值賦值給變量str1和str2后,str1和str2都指向了堆中同一對象。
我們再來看一段代碼:
public class Test1 {
public static void main(String[] args) {
System.out.println("abc"=="abc"); //true
System.out.println(new String("abc")==new String("abc")); // false
}
看了上面這段代碼,估計(jì)很多人不敢相信這樣的結(jié)果,那么就在電腦上自己敲一遍。要理解上述結(jié)果的差異,我們需要知道String是一種特殊的包裝類數(shù)據(jù)類型,它不屬于8種基本數(shù)據(jù)類型,但是我們可以像基本數(shù)據(jù)類型那樣,不通過new的方法在棧中直接創(chuàng)建String類型數(shù)據(jù),且也是共享的,意思是棧中只存在一個(gè)“abc”,因此比較的兩個(gè)“abc”實(shí)際上是同一個(gè)。
而通過new()方法創(chuàng)建的兩個(gè)String類型對象存放于堆中,雖然在棧中沒有創(chuàng)建String類型的引用變量指向他們,但是還是比較的是兩個(gè)對象的地址值。提示:只有通過new()方法才能保證每次都創(chuàng)建一個(gè)新的對象。
(二) equals方法
那如何才能判斷兩個(gè)引用類型變量所指向?qū)ο蟮膬?nèi)容是否相等呢?這時(shí)候該equals上場了。equals方法是基類Object中的方法,因此對于所有的繼承于Object的類都會(huì)有該方法。要理解equals方法的作用,看源碼是個(gè)比較好的方法。
另需注意:equals方法不能作用于基本數(shù)據(jù)類型的變量。
(三)總結(jié)
(1)對于==,如果作用于基本數(shù)據(jù)類型的變量,則直接比較其存儲(chǔ)的 “值”是否相等;如果作用于引用類型的變量,則比較的是所指向的對象的地址。
(2)對于equals方法,如果沒有對equals方法進(jìn)行重寫,則比較的是引用類型的變量所指向的對象的地址。諸如String、Date等類對equals方法進(jìn)行了重寫的話,比較的是所指向的對象的內(nèi)容。
(3)對于引用類型的變量,用“==”比較返回true的結(jié)果,那么用equals方法比較也一定返回true。