1. 程式人生 > >謎題13:畜牧場

謎題13:畜牧場

連接 nal string dog animal true 寫法 java static

George Orwell的《畜牧場(Animal Farm)》一書的讀者可能還記得老上校的宣言:“所有的動物都是平等的。”下面的Java程序試圖要測試這項宣言。那麽,它將打印出什麽呢?


public class AnimalFarm{

    public static void main(String[] args){

        final String pig = "length: 10";

        final String dog = "length: " + pig.length();

        System.out. println("Animals are equal: "

                            + pig == dog);

    }

}

對該程序的表面分析可能會認為它應該打印出Animal are equal: true。畢竟,pig和dog都是final的string類型變量,它們都被初始化為字符序列“length: 10”。換句話說,被pig和dog引用的字符串是且永遠是彼此相等的。然而,==操作符測試的是這兩個對象引用是否正好引用到了相同的對象上。在本例中,它們並非引用到了相同的對象上。

你可能知道String類型的編譯期常量是內存限定的。換句話說,任何兩個String類型的常量表達式,如果標明的是相同的字符序列,那麽它們就用相同的對象引用來表示。如果用常量表達式來初始化pig和dog,那麽它們確實會指向相同的對象,但是dog並不是用常量表達式初始化的。既然語言已經對在常量表達式中允許出現的操作作出了限制,而方法調用又不在其中,那麽,這個程序就應該打印Animal are equal: false,對嗎?

嗯,實際上不對。如果你運行該程序,你就會發現它打印的只是false,並沒有其它的任何東西。它沒有打印Animal are equal: 。它怎麽會不打印這個字符串字面常量呢?畢竟打印它才是正確的呀!謎題11的解謎方案包含了一條暗示:+ 操作符,不論是用作加法還是字符串連接操作,它都比 == 操作符的優先級高。因此,println方法的參數是按照下面的方式計算的:


System.out.println(("Animals are equal: " + pig) == dog);

這個布爾表達式的值當然是false,它正是該程序的所打印的輸出。

有一個肯定能夠避免此類窘境的方法:在使用字符串連接操作符時,總是將非平凡的操作數用括號括起來。更一般地講,當你不能確定你是否需要括號時,應該選擇穩妥地做法,將它們括起來。如果你在println語句中像下面這樣把比較部分括起來,它將產生所期望的輸出Animals are equal: false :


System.out.println("Animals are equal: " + (pig == dog));

可以論證,該程序仍然有問題。

如果可以的話,你的代碼不應該依賴於字符串常量的內存限定機制。內存限定機制只是設計用來減少虛擬機內存占有量的,它並不是作為程序員可以使用的一種工具而設計的。就像這個謎題所展示的,哪一個表達式會產生字符串常量並非總是很顯而易見。

更糟的是,如果你的代碼依賴於內存限定機制實現操作的正確性,那麽你就必須仔細地了解哪些域和參數必定是內存限定的。編譯器不會幫你去檢查這些不變量,因為內存限定的和不限定的字符串使用相同的類型(String)來表示的。這些因在內存中限定字符串失敗而導致的bug是非常難以探測到的。

在比較對象引用時,你應該優先使用equals方法而不是 == 操作符,除非你需要比較的是對象的標識而不是對象的值。通過把這個教訓應用到我們的程序中,我們給出了下面的println語句,這才是它應該具有的模樣。很明顯,在用這種方式訂正了該程序之後,它將打印出true:


System.out.println("Animals are equal: " + pig.equals(dog));

這個謎題對語言設計者來說有兩個教訓。

1,字符串連接的優先級不應該和加法一樣。這意味著重載 + 操作符來執行字符串連接是有問題的,就像在謎題11中提到的一樣。

2,還有就是,對於不可修改的類型,例如String,其引用的等價性比值的等價性更加讓人感到迷惑。也許 == 操作符在被應用於不可修改的類型時應該執行值比較。要實現這一點,一種方法是將 == 操作符作為equals方法的簡便寫法,並提供一個單獨的類似於System.identityHashCode的方法來執行引用標識的比較。

謎題13:畜牧場