我一直在閱讀Bloch和Gafter的Java Puzzlers,並進入拼圖10(Tweedledee)。這個難題的實質是如何使E1 + = E2非法,而E1 = E1 + E2合法?
爲變量提供報關單
x
和i
這樣,這是一個法律聲明:x = x + i;
但這不是:
x += i;
根據這本書,解決這個問題的方法如下:
Object x = "Buy ";
String i = "Effective Java!";
該書聲稱,在+=
運算符中,只有當左邊表達式的類型爲String
時,右邊表達式纔可以是任何類型。不過,我試着運行這段代碼,它編譯並運行沒有任何問題。
然後我深入研究了Java語言規範。第15.26.2節討論了兩種情況:左邊的表達式是數組訪問表達式,而不是。如果左邊的操作數表達式不是數組訪問表達式,那麼JLS不會說左邊的表達式是String。當它是,這部分應用:
如果T是一個引用類型,那麼它必須是字符串。因爲class String是最後一個類 ,所以S必須也是String。因此, 複合賦值運算符從不需要簡單賦值運算符所需的運行時檢查 。
❖陣列組件的保存的值和右側 操作數的值被用來執行二進制運算(字符串連接) 通過化合物賦值運算符表示(這是必然 + =)。如果此操作突然完成,則由於同樣的原因,分配表達式 會突然完成並且不會發生分配。
T這裏是在編譯時確定的左側操作數的類型,S是選定的數組組件。所以我想我會改變我的代碼到這一點:
Object[] x = {new Object()};
String i = "Effective Java!";
x[0] += i;
但即使是這種代碼編譯,沒有任何問題,運行即使new Object()
甚至不是一個遠程String
。
這是怎麼發生的?這是否意味着Java編譯器偏離了JLS?還有可能以某種方式解決原始的難題?
你有沒有試過創建一個覆蓋'toString'打印到stdout/stderr的對象? – 2013-01-08 15:35:52
你確定應該編譯哪一個?或者,也許這本書有一個錯字。例如,如果x和i是字節,那麼'x + = i;'是有效的,但是'x = x + i;'不是。 –
你確定你確實測試過'x + = i'而不是'i + = x'嗎?我的意思是(String)+ =(Object)很容易編譯,當(Object)+ =(String)不能編譯時。 –