1. 程式人生 > >從Java記憶體分配來看equals和==比較

從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虛擬機器)

   

下面是簡易的記憶體分配

從這裡可以看出str1str2指向的是兩塊不同的記憶體區域,也就是兩個不同的物件,所以==比較為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;
}

我們知道StringJava的類,如果是自己建立的類呢,還會是一樣的效果嗎。比如建立一個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));
    }
}
      結果是false
,這又是為什麼呢。不知道你有沒有注意到我們寫的Value類中根本沒有equals方法,結果卻能呼叫,那一定是呼叫了父類Object中的方法,我們來看一下Objectequals方法是怎麼寫的。

public 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