用於比較字串的陷阱
Java 初學者的一個常見錯誤是使用 ==
運算子來測試兩個字串是否相等。例如:
public class Hello {
public static void main(String[] args) {
if (args.length > 0) {
if (args[0] == "hello") {
System.out.println("Hello back to you");
} else {
System.out.println("Are you feeling grumpy today?");
}
}
}
}
上面的程式應該測試第一個命令列引數並列印不同的訊息,而不是單詞 hello
。但問題是它不起作用。該計劃將輸出“你今天感覺脾氣暴躁嗎?” 無論第一個命令列引數是什麼。
在這種特殊情況下,String``hello
放在字串池中,而 String
args [0]駐留在堆上。這意味著有兩個物件代表相同的文字,每個物件都有它的參考。由於 ==
測試引用而非實際相等,因此比較將在大多數時間產生錯誤。這並不意味著它總會這樣做。
當你使用 ==
測試字串時,你實際測試的是兩個 String
物件是否是同一個 Java 物件。不幸的是,這不是 Java 中字串相等的含義。實際上,測試字串的正確方法是使用 equals(Object)
方法。對於一對字串,我們通常要測試它們是否由相同順序的相同字元組成。
public class Hello2 {
public static void main(String[] args) {
if (args.length > 0) {
if (args[0].equals("hello")) {
System.out.println("Hello back to you");
} else {
System.out.println("Are you feeling grumpy today?");
}
}
}
}
但它實際上變得更糟。問題是 ==
會在某些情況下給出預期的答案。例如
public class Test1 {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
if (s1 == s2) {
System.out.println("same");
} else {
System.out.println("different");
}
}
}
有趣的是,這將列印相同,即使我們以錯誤的方式測試字串。這是為什麼?因為 Java 語言規範(第 3.10.5 節:字串文字) 規定任何兩個由相同字元組成的字串>> literals <<實際上將由同一個 Java 物件表示。因此,==
測試將給出相同的文字。 (字串文字是 interned
並在載入程式碼時新增到共享的字串池,但這實際上是一個實現細節。)
為了增加混淆,Java 語言規範還規定,當你有一個連線兩個字串文字的編譯時常量表示式時,它相當於一個文字。從而:
public class Test1 {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hel" + "lo";
String s3 = " mum";
if (s1 == s2) {
System.out.println("1. same");
} else {
System.out.println("1. different");
}
if (s1 + s3 == "hello mum") {
System.out.println("2. same");
} else {
System.out.println("2. different");
}
}
}
這將輸出“1. same”和“2. different”。在第一種情況下,+
表示式在編譯時進行評估,我們將一個 String
物件與自身進行比較。在第二種情況下,它在執行時進行評估,我們比較兩個不同的 String
物件
總之,使用 ==
在 Java 中測試字串幾乎總是不正確的,但不能保證給出錯誤的答案。