用於比較字串的陷阱

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 中測試字串幾乎總是不正確的,但不能保證給出錯誤的答案。