書藉基本資料: Java Puzzler中文版-陷阱、錯誤與死角
和《Effective Java》類似,這本在講Java的特性。不同的是,這本著重在以易犯的錯誤例子來說明正確的準則,而《Effective Java》是直述守則。本書在說明錯誤時,常引用別處文獻說明進一步資訊上那找,其中大部份的參考文獻出自《Effective Java》。另外不同的一點,本書的述說語氣比較風趣,偶而還有有趣的爛解答。哦,還有附一堆相當傷眼的錯覺圖,我時常用手遮住它們,以方便我能舒服地閱讀文字。然而兩本相較之一下,《Effective Java》較值得看。
不過相較於《Effective Java》直接說怎麼做較好,這本書到是相當成功地說服讀者,為什麼不要那麼做,例子舉得相當漂亮,帶來不少衝擊。本書不宜長時間連續閱讀,讀起來相當傷腦,一堆看似正常的程式碼,卻常發生不可思議的結果,或是不知所云的編譯錯誤訊息。或許,當Java寫到一定程度時,看這本書可以協助除錯。以下簡單直述部份心得,若對解謎有興趣的話,就別看下面的心得,自己慢慢翻書也是種樂趣。
- final對於method和field的含意不同,field的final是指只能設值一次,所以
final int a;
a = 3;是合法的。但也因這個特性,會有些潛在問題,例如:物件因為初始化順序不同,而讀到未初始化的final field。解法:lazy initialization。
- 除非之前有執行 System.exit(),finally一定會被執行到,這意味著在finally之前的return和throws exception會被finally給蓋過!。
- constructor內不要呼叫被覆寫的method,有可能因物件初始順序而讀到未初始化的欄位。可用lazy initialization解決。
- 一些計算機組織的知識,像是 IEEE 754對浮點數的定義,使得太小的小數無法加進去,例如:
float a = 2.0E20f;
a += 1.0; // 結果仍是2.0E20f還有因為負數用二補數表示,負的MIN_VALUE不存在對應的正數,abs(MIN_VALUE)結果仍是負的MIN_VALUE。
- 要分清楚overriding、overloading、hiding、shadowing、obscuring。Java 5.0後,override時記得加 @override 避免 method 寫錯宣告時變成 overloading。還有別用參數數同一樣且有父子關係的 overloading,例如下面是個不好的 overloading,由於 JVM 會找最接近型態的,而可能呼叫到非你想要的:
public boolean equals(Object o) {return true; }
public boolean equals(String o) {return true; } - method的覆寫 (override)不能變得更限制(例如public不能變protected),但field可以,此時稱為 hiding(亦有其它情況會發生 hiding),例如下面的例子是合法的:
class A { public static String s = “A”; }
class B extends A { private static String s = “B”; }
A o = new B();
System.out.println(o.s); // 結果為:A - 用class method時,使用class名稱呼叫,避免呼叫錯誤。注意:((Math)null).PI 是合法的,JVM不會理會object,而會直接找它的class。
- Java 5.0支援泛型後,盡量不要使用原始類型(例如 List),那是向下相容的必要之惡;改使用參數化類型(例如 List<T>)。千萬不要混用原始類型和參數化類型,#88會給你滿意的理由,為何不要這麼做。
- 不要在一個運算式裡改變一個變數多次,這牽涉到實作細節,比方 x^=y^=x^=y 這個有名的例子,在 Java 裡不會成功的 swap。
- 不要在一個運算式裡將型態自動向上向下轉型(例如 int 變 long或反過來),這之間有很多潛在問題,詳情參閱前面的puzzles。
- char是無號型態,其它byte、int等都是有號的;16進位沒有正負號,它直接以二補數解讀;< <、>>等只看最低的5 bits數,a < < 31和a << 63意思一樣(小心負數的情況)。
沒有留言:
張貼留言