之前有在 Java字串比較(3種方法)以及對比 C++ 時的注意項 中寫過一點關於 equals()與==的比較,但最近的Java考試複習過程中發現有部分情況沒涉及到,故重新學習一下
在編寫程式碼的時候我們經常會使用 equals
和 ==
來判斷兩個物件是否相等,那麼兩者有什麼區別呢,主要有以下幾點區別:
-
首先的區別是,equals 是方法,而 == 是操作符;
-
對於基本型別的變數來說(如
short
、int
、long
、float
、double
),只能使用 == ,因為這些基本型別的變數沒有 equals 方法。對於基本型別變數的比較,使用 == 比較, 一般比較的是它們的值。 -
對於引用型別的變數來說(例如 String 類)才有 equals 方法,因為 String 繼承了 Object 類, equals 是 Object 類的通用方法。對於該型別物件的比較,預設情況下,也就是沒有複寫 Object 類的 equals 方法,使用 == 和 equals 比較是一樣效果的,都是比較的是它們在記憶體中的存放地址。但是對於某些類來說,為了滿足自身業務需求,可能存在 equals 方法被複寫的情況,這時使用 equals 方法比較需要看具體的情況,例如 String 類,使用 equals 方法會比較它們的值;
對於上述第三點理解起來可能有點複雜,因為這裡 equals 方法比較需要分兩種情況來討論,一種情況是該方法沒有被重寫,另外一種是該方法被重寫。
-
對於 equals 方法沒有被重寫的情況。如果類沒有重寫該方法,那麼預設使用的就是 Object 類的方法,以下是 Object 類的 equals 方法:
public boolean equals(Object obj) { return (this == obj); }
從原始碼可以看出,裡面使用的就是 ==
比較,所以這種情況下比較的就是它們在記憶體中的存放地址。
-
對於
equals
方法被重寫的情況。以 String 類為例,以下是 String 類中的 equals 方法:@Override public boolean equals(Object other) { if (other == this) { return true; } if (other instanceof String) { String s = (String)other; int count = this.count; if (s.count != count) { return false; } if (hashCode() != s.hashCode()) { return false; } char[] value1 = value; int offset1 = offset; char[] value2 = s.value; int offset2 = s.offset; for (int end = offset1 + count; offset1 < end; ) { if (value1[offset1] != value2[offset2]) { return false; } offset1++; offset2++; } return true; } else { return false; } }
從原始碼可以看出, String 類複寫了 equals 方法,當使用 == 比較記憶體的存放地址不相等時,接下來會比較字串的內容是否 相等,所以 String 類中的 equals 方法會比較兩者的字串內容是否一樣。我們來看看下面的例子:
String a = "Hello World";
String b = new String("Hello World");
String c = b; //引用傳遞
System.out.println("a == b:" + a == b); //false
System.out.println("b == c:" + b == c); //true
System.out.println("a == c:" + a == c); //false
System.out.println("a.equals(b):" + a.equals(b)); //true
System.out.println("b.equals(c):" + b.equals(c)); //true
System.out.println("a.equals(c):" + a.equals(c)); //true
最終的列印會是:
a == b:false
b == c:true
a == c:false
a.equals(b):true
b.equals(c):true
a.equals(c):true
因為 String b 通過 new 的方式已經開闢了新的堆記憶體,而 String a = "Hello World" 是存放在常量池裡的,兩者在 Java 記憶體裡存在放的位置是不同的,所以 a == b 為 false;而 equals 方法當兩者存放的記憶體地址不同時,會比較兩者的值,兩者的值都是 "Hello World" ,所以 a.equals(b) 為 true。
另外請思考一下下方程式碼的執行結果為什麼是 True、false
public class Java_epuals {
public static void main(String[] args) {
Integer i2 = 10;
Integer i3 = 10;
System.out.println(i2 == i3); // true
Integer i4 = 128;
Integer i5 = 128;
System.out.println(i4 == i5); // false
}
}
對於 i2
和 i3
的比較,因為變數的定義方法是 i2(i3) = 10
它們的變數會置於常量區,兩個變數的記憶體地址相同。
此時 ==
返回 true
。
那麼為什麼 i4
和 i5
是返回 false
呢?
這是因為 Java 中 integer 範圍取值要在-128到+127 (為什麼Integer物件範圍(-128-127)之間),而我們賦的值是 128 ,此時變數並不在常量區定義。所以兩個變數的記憶體地址不同,==
返回 false