Java 中 == 與 equals() 方法的區別

== 與 equals() 都有比較兩者是否相等的意思, == 用於比較兩個操作數的值是否相等,equals() 默認是對 == 的封裝,通常需要自定義重寫來定義不同的相等條件

關係操作符 ==

== 屬於關係操作符,關係操作符用於比較兩個操作數的值之間的關係,在 Java 的內存結構中,基本數據類型是直接存放在操作數棧中的,而對象則是存放在堆內存中,在操作數棧中存放的是堆中對象的引用地址。對於基本數據類型,其操作數的值就是基本數據類型的值,而對於對象,其操作數的值是對象的引用地址,因此在對基本數據類型使用 == 進行比較時,能夠直接比較兩者的值,得到想要的結果,而對象如果使用 == 進行比較,比較的就是對象的引用地址,這樣即使兩個對象的內容完全相等,由於地址不相等,得到的就不是想要的結果了

 public static void main(String[] args) {
        Integer n1 = new Integer(11);//創建 Integer 類的對象
        Integer n2 = new Integer(11);
        System.out.println(n1 == n2);
        int n3 = 11;//創建 int 類型數據
        int n4 = 11;
        System.out.println(n3 == n4);
    }

輸出結果:

false
true

從運行結果中分析,n1 和 n2 是Integer 類的對象,因此在操作數棧中存放的是他們的引用地址,使用 == 比較時,地址不相同,因此結果爲 false,而 n3 和 n4 是 int 類型數據,操作數棧中存放的就是 11 這個值,因此返回結果爲 true

值得注意的是 String 類型的數據,按照上面描述的,String 不屬於基本數據類型,也就是他在操作數棧中存放的也是引用地址,那按理說對兩個具有相同值的 String 類型數據使用 == 比較,結果也應該是 false,然後事實並不是這樣:

 public static void main(String[] args) {
        String s1 = new String("str");//創建 String 類對象
        String s2 = new String("str");
        System.out.println(s1 == s2);
        String s3 = "str";
        String s4 = "str";
        System.out.println(s3 == s4);
    }

輸出結果:

false
true

從結果中分析,對於 s1 == s2 返回 false 很好理解,因爲 s1 與 s2 是兩個對象,在操作數棧中存放的是他們的引用地址,兩者地址不相等,所以返回 false。

補充一下,在使用 String s1 = new String(“str”) 時,實際上是創建了兩個對象,一個是在字符串緩衝池中創建一個”str”對象,另一個是在堆上創建一個指向 “str” 的String 類型對象,而這裏的 s1 和 s2 都指向的是堆上的對象。更多關於 String 的內容可以參考 這篇關於 String 的文章這篇關於 String 中的 intern 方法的文章

對於 s3 == s4 的返回結果,會有一點點疑問:既然 String 類型的 s3 和 s4 是引用類型,那在操作數棧中存放的是他們的引用地址,爲什麼返回結果爲true,難道他們的引用地址相等?答案是:是的。這是因爲在程序運行時,會創建一個字符串緩衝池,在創建String 類型數據 s3 的時候,首先會從字符串緩衝池中尋找具有相同值的對象,如果有就直接將 s3 指向這個已有的對象,如果沒有才新建一個,這樣,顯然執行 s3 == “str” 時,字符串緩衝池中是沒有相同值的對象,因此需要新建一個 “str” 對象,而在執行 s4 == “str” 時,檢查字符串緩衝池,發現已經有一個 “str” 對象了,於是 s4 直接指向這個 str,到此,s3 和 s4 指向的就是同一個對象了,也就是說他們在操作數棧中存放的對象引用地址是同一個,當然就相等了。

Object 中的方法 equals()

由於 == 只能比較兩個操作數的值之間的關係,那如果想要比較兩個對象的值之間的關係呢,這時就需要用到 equals() 方法了,equals() 是 Object 類中的方法,在 Java 中,Object 類是所有類的父類,所以只要是 java 中的類,都有 equals() 方法。在 Object 類中的 equals() 方法如下:

 public boolean equals(Object obj) {
        return (this == obj);
    }

可以看到,equals() 默認其實也是使用 == 來進行比較的,即:equals() 方法默認比較兩個對象的地址,對於特定的類,需要重寫 equals() 方法,來達到想要的目的,就像在 String 類中,其 equals() 方法是這樣的:

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 類中的 equals() 方法可以看出,判斷兩個字符串是否相等需要滿足的條件是:

  • 兩者的地址相同,即兩者是同一個對象

或者

  • 兩者的長度相同並且兩者中每一個字符都相同

因此,equals() 方法是需要根據特定的類重寫特定的邏輯,通常同時需要重寫 hashCode() 方法,hashCode() 方法返回一個與對象的地址相關的值,對於 Object 中默認的 hashCode() 方法,僅當兩個對象的地址相等時,他們的 hashCode() 返回值才相等。在 String 類中,重寫了 hashCode() 方法,使得 hashCode() 方法不再與地址相關,這樣做是爲了保證用 equals() 比較返回爲 true 的兩個對象,他們的 hashCode() 返回值也是根據相關邏輯得到的一個相同的值

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章