蔡學鏞專欄:全世界所有程式設計師都會犯的錯誤 (轉)
當年,國際巨星成龍的「龍種」曝光,眾人指責他對不起嬌妻林鳳嬌,逼得他出面召開記者會,向世人自白他犯了「全世界所有男人都會犯的錯誤」。從來沒犯過這種錯誤的我,也因此常常認為自己不是個男人。
雖然沒犯過「全世界所有男人都會犯的錯誤」,但是我倒是曾經犯了「全世界所有員都會犯的錯誤」。不管使用何種語言,全世界所有程式設計師都一定犯過這種錯誤,那就是:太依賴,卻不知道編譯器做了哪些事。
一般來說,越高階的程式語言,會提供越多語法上的便利,以方便程式撰寫,這就俗稱為syntactic sugar,我稱其為「語法上的甜頭」。雖說是甜頭,但是如果你未能瞭解該語法的實質內涵,很可能會未嘗甜頭,卻吃盡苦頭。
不久前,我收到一個電子,讀者列出下面的程式,向我求救。看過這個程式之後,我確定這又是一個「全世界所有程式設計師都會犯的錯誤」。
// 程式1
class Singleton {
private static Singleton obj = new Singleton();
public static int counter1;
public static int counter2 = 0;
private Singleton() {
counter1++;
counter2++;
}
public static Singleton getInstance() {
return obj;
}
}
// 程式2
public class MyMain {
public static void main(String[] args) {
Singleton obj = Singleton.getInstance();
System.out.println("obj.counter1=="+obj.counter1);
System.out.println("obj.counter2=="+obj.counter2);
}
}
結果是:
obj.counter1==1
obj.counter2==0
你有沒有被此結果嚇一跳?乍看程式程式碼,你很可能會認為counter1和counter2的值一定會相等,但執行結果顯然不是如此。其實,程式1被編譯後的程式應該等同於下面的程式3:
// 程式3
class Singleton {
private static Singleton obj;
public static int counter1;
public static int counter2;
static { // 這就是class constructor
// 在進入此class constructor之前,class已經被JVM
// 好,所有的static field都會被先設定為0,
// 所以此時counter1和counter2都已經是0,且singleton為null
obj = new Singleton(); // 問題皆由此行程式產生
// counter1不會在此被設定為0
counter2 = 0; // counter2再被設定一次0(其實是多此一舉)
}
private Singleton() { // 這是instance constructor
counter1++;
counter2++;
}
public static Singleton getInstance() {
return obj;
}
}
這是因為:當class具有static field,且直接在宣告處透過「=...」的方式設定其值時,編譯器會自動將這些敘述依序搬到class constructor內。同樣地,當class具有instance field,且直接在宣告處透過「=...」的方式設定其值時,編譯器會自動將這些敘述依序搬到instance constructor內。
此程式在class constructor內,還未將static field初始化時(這時候,counter1和counter2都是0),就呼叫instance constructor,而instance constructor竟然還會去更動static field的值,使得counter1和counter2都變成1。然後instance constructor執行完,回到class constructor,再把counter2的值設為0(但是
counter1維持不變)。最後的結果:counter1等於1,counter2等於0。
欲改正程式1,方法有三:
-方法一:將singleton field的宣告調到counter1與counter2 field之後。
這是最好的作法。
-方法二:將counter2=0的宣告中,「=0」的部分刪除。這種作法只有在希望
-方法三:將初始化的動作搬到class constructors內,自行撰寫,而不依賴
編譯器產生。這是最保險的作法。
如何避免犯下「全世界所有程式設計師都會犯的錯誤」,我給各位Java程式設計師
的建議是:
-熟讀Java Language Specification
-在有疑問時,使用J2SDK所提供的javap來反組譯Java Bytecode,直接觀察
編譯後的結果。
下面是我用javap來反組譯程式1的示範:
C:>javap -c -classpath . Singleton
Compiled from MyMain.java
class Singleton extends java.lang. {
public static int counter1;
public static int counter2;
public static Singleton getInstance();
static {};
}
Method Singleton()
0 aload_0
1 invokespecial #1
4 getstatic #2
7 iconst_1
8 iadd
9 putstatic #2
12 getstatic #3
15 iconst_1
16 iadd
17 putstatic #3
20 return
Method Singleton getInstance()
0 getstatic #4
3 areturn
Method static {}
0 new #5
3 dup
4 invokespecial #6
7 putstatic #4
10 iconst_0
11 putstatic #3
14 return
其實Java的syntactic sugar並不算多,的syntactic sugar才真的是無所不在,
也因此C#的初學者更容易犯了「全世界所有程式設計師都會犯的錯誤」。許多C#的書都會一邊介紹C#語法,一邊介紹編譯之後MSIL(的中間語言,類似Java的Bytecode)的結果,然而Java的書卻鮮少這麼做。
雖說是「全世界所有程式設計師都會犯的錯誤」,但是這不代表你犯了此錯誤之後,仍可以同愛借錢的曹啟泰一般地「抬頭挺胸、理直氣壯」。只要有心,其實這一類的錯誤仍是可以避免的。
本文作者:蔡學鏞
文章出處:Sleepless 2.0
發表日期:03/10/
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992935/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 程式設計師的苦與樂:一開始程式設計師可能會犯的錯誤,真是太真實了!程式設計師
- Java程式設計師可能會犯的幾個錯誤, 看看你是不是躺槍了?Java程式設計師
- 工程師犯的最大錯誤?工程師
- 90%的Java開發人員都會犯的5個錯誤Java
- Java初學者容易犯的程式碼錯誤Java
- 程式設計師都遇到過哪些誤解?程式設計師
- 9 條 PHP 程式設計小知識及易犯的小錯誤PHP程式設計
- (網頁)Java程式設計師們最常犯的10個錯誤(轉)網頁Java程式設計師
- 這些錯誤你都犯過嗎?來看看9大XMind初學者常見錯誤!
- 更好的前端設計形式——設計者犯的常見錯誤及修改方法前端
- 有哪些錯是Java程式設計師在面試中最容易犯的呢?Java程式設計師面試
- Java初學者容易犯哪些錯誤?Java
- golang中經常會犯的一些錯誤Golang
- 你信不信?初學C語言的人都犯過這些低階的錯誤!C語言
- 學Python的程式設計師,程式設計能力都“退化”成什麼樣了?Python程式設計師
- 程式設計師毒雞湯:我們都該學會正確的失敗程式設計師
- 漫畫 | 外行對程式設計師誤會有多深!程式設計師
- 每個程式設計師都會的 35 個 jQuery 小技巧程式設計師jQuery
- android開發中犯的小錯誤,不要學我!Android
- 好程式設計師分享JavaScript幾個最常見的錯誤程式設計師JavaScript
- 你會犯這些 Go 編碼錯誤嗎(二)?Go
- 那些學了 Python 的程式設計師,程式設計能力都“退化”成什麼樣了?Python程式設計師
- 程式設計師如何玩轉《衝頂大會》?程式設計師
- Java程式設計師都需要懂的「反射」Java程式設計師反射
- Java 程式設計師都該懂的 HashMapJava程式設計師HashMap
- macOS小白容易犯的24個錯誤Mac
- UI設計師必備技能,看看你都學會了嗎UI
- 為什麼程式設計師在學習程式設計的時候什麼都記不住?程式設計師
- 程式設計師應當學會“偷懶”程式設計師
- 程式設計師寫的跳轉程式設計師
- #程式設計師因犯錯被領導收回獎金!網友:看似賞罰分明,安排程式設計師
- 大廠程式設計師的除錯技巧,偷學到了!程式設計師除錯
- 聰明的程式設計師容易做出錯誤的戰略決策 - earthly程式設計師
- 程式設計師都幹些什麼?程式設計師
- 5 個 Linux 新手會犯的失誤Linux
- 專科程式設計師,學歷可能會成為發展障礙程式設計師
- 開發時犯得小錯誤
- go新手容易犯的三個致命錯誤Go
- 使用 Kubernetes 最容易犯的 10 個錯誤!