從Java記憶體分配來看equals和==比較
剛開始學Java的時候,遇到equals比較和==比較有時候結果總是讓人驚訝,如果是以前沒有接觸過程式設計,不明白記憶體分配,每次都是稀裡糊塗的記住一些結果。這種是true那種是false,但具體是為什麼,具體自己應該怎麼去分析才能分析出程式應該有的結果,今天我們就從Java記憶體分配的角度來聊聊。
先上程式碼:
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1==str2);
System.out.println(str1!=str2);
結果false true
==比較str1和str2的結果是false,也就是他們是不等的。這裡首我們要明白==比較的是什麼,==比較的是他們在記憶體中的地址,也就是他們是否是同一個物件。我們來看String str1 = new String("abc");這句話做了什麼事,遇到new關鍵字會做三件事:
1、 開闢一塊堆記憶體空間用於存放物件(這塊空間會有一個地址)
2、 建立一個新的物件放入開闢的記憶體空間
3、 將str1引用指向這塊記憶體空間
我們看一下Java虛擬機器執行時資料區記憶體劃分(圖片來源深入理解Java虛擬機器)
下面是簡易的記憶體分配
從這裡可以看出str1和str2指向的是兩塊不同的記憶體區域,也就是兩個不同的物件,所以==比較為false。但我們想要的是並不是想知道他們是不是同一個物件,我們想知道它們的值想不想等,這時候就需要使用到equals方法。比如上面的程式System.out.println(str1.equals(str2));就會出現true,這是比較的才是它們的值。下面是String類原始碼中實現的equals()
public boolean equals(Object anObject) { //比較是否是同一個物件,如果是同一個物件那一定是true 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的類,如果是自己建立的類呢,還會是一樣的效果嗎。比如建立一個Value
class Value{
int i;
}
public class TestDemo {
public static void main(String[] args) {
Value v1 = new Value();
Value v2 = new Value();
v1.i = v2.i = 100;
System.out.println(v1.equals(v2));
}
}
結果是falsepublic boolean equals(Object obj) {
return (this == obj);
}
返回了是否==,也就是equals方法的內部實現是判斷是否==,這也與我們的本意不符。怎麼辦呢?這時候要想比較自己定義的類的例項是否相等,就必須重寫equals方法,具體怎樣才算相等,就看你自己的實現了。
class Value{
int i;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Value value = (Value) o;
return i == value.i;
}
@Override
public int hashCode() {
return i;
}
}
public class TestDemo {
public static void main(String[] args) {
Value v1 = new Value();
Value v2 = new Value();
v1.i = v2.i = 100;
System.out.println(v1.equals(v2));
}
}
輸出結果true