成人午夜激情影院,小视频免费在线观看,国产精品夜夜嗨,欧美日韩精品一区二区在线播放

當前位置:首頁>>開發編程>>JAVA>>新聞內容
全世界所有程序員都會犯的錯誤
作者:蔡學鏞 發布時間:2003-10-7 14:30:08 文章來源:Sleepless 2.0

當年,國際巨星成龍的「龍種」曝光,眾人指責他對不起嬌妻林鳳嬌,逼得他出面召開記者會,向世人自白他犯了「全世界所有男人都會犯的錯誤」。從來沒犯過這種錯誤的我,也因此常常認為自己不是個男人。

雖然沒犯過「全世界所有男人都會犯的錯誤」,但是我倒是曾經犯了「全世界所有程序員都會犯的錯誤」。不管使用何種語言,全世界所有程序員都一定犯過這種錯誤,那就是:太依賴編譯器,卻不知道編譯器做了哪些事。

一般來說,越高階的程序語言,會提供越多語法上的便利,以方便程序撰寫,這就俗稱為syntactic sugar,我稱其為「語法上的甜頭」。雖說是甜頭,但是如果你未能了解該語法的實質內涵,很可能會未嘗甜頭,卻吃盡苦頭。

不久前,我收到一個電子郵件,讀者列出下面的Java程序,向我求救。看過這個程序之后,我確定這又是一個「全世界所有程序員都會犯的錯誤」。

// 程序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.Object {
    public static int counter1;
    public static int counter2;
    public static Singleton getInstance();
    static {};
}

Method Singleton()
   0 aload_0
   1 invokespecial #1 <Method java.lang.Object()>
   4 getstatic #2 <Field int counter1>
   7 iconst_1
   8 iadd
   9 putstatic #2 <Field int counter1>
  12 getstatic #3 <Field int counter2>
  15 iconst_1
  16 iadd
  17 putstatic #3 <Field int counter2>
  20 return

Method Singleton getInstance()
   0 getstatic #4 <Field Singleton obj>
   3 areturn

Method static {}
   0 new #5 <Class Singleton>
   3 dup
   4 invokespecial #6 <Method Singleton()>
   7 putstatic #4 <Field Singleton obj>
  10 iconst_0
  11 putstatic #3 <Field int counter2>
  14 return

其實Java的syntactic sugar并不算多,C#的syntactic sugar才真的是無所不在,
也因此C#的初學者更容易犯了「全世界所有程序員都會犯的錯誤」。許多C#的書都會一邊介紹C#語法,一邊介紹編譯之后MSIL(.NET的中間語言,類似Java的Bytecode)的結果,然而Java的書卻鮮少這么做。

雖說是「全世界所有程序員都會犯的錯誤」,但是這不代表你犯了此錯誤之后,仍可以同愛借錢的曹啟泰一般地「抬頭挺胸、理直氣壯」。只要有心,其實這一類的錯誤仍是可以避免的。


本文作者:蔡學鏞
文章出處:Sleepless 2.0
發表日期:03/10/2003


最新更新
·Java開發技術十年的回顧與展
·關于TOMCAT主目錄與虛擬目錄
·用java程序調用ffmpeg執行視
·JavaBean與Enterprise JavaB
·Java開發人員的十大戒律
·JavaFX Script將終結AJAX?還
·解決IE中所有png圖片透明問題
·JSP解決地址欄中傳遞中文字符
·Eclipse五歲了:Java程序員的
·審查Java代碼的十一種常見錯
相關信息
放生
愚愛
夠愛
觸電
白狐
心跳
知足
犯錯
降臨
分愛
葬愛
光榮
畫心
火花
稻香
愛得起
這種愛
大丈夫
花蝴蝶
二缺一
小酒窩
下雨天
右手邊
安靜了
棉花糖
明天過后
邊做邊愛
擦肩而過
沒有如果
懷念過去
等一分鐘
越來越愛
寂寞暴走
你的承諾
Nobody
我們都一樣
永遠在身邊
天使的翅膀
原諒我一次
i miss you
原諒我一次
吻的太逼真
姑娘我愛你
做你的愛人
一定要愛你
飛向別人的床
愛上別人的人
感動天感動地
心在跳情在燒
不潮不用花錢
如何能把你忘記
即使知道要見面
愛上你是一個錯
最后一次的溫柔
愛上你是我的錯
怎么會狠心傷害我
親愛的那不是愛情
傷心時候可以聽情歌
愛上你等于愛上了錯
不是因為寂寞才想你
主站蜘蛛池模板: 渝中区| 临沭县| 台州市| 体育| 古交市| 会泽县| 崇仁县| 海口市| 新化县| 新津县| 绍兴县| 抚远县| 乐亭县| 临潭县| 延庆县| 旅游| 新巴尔虎右旗| 遂宁市| 灵宝市| 全椒县| 肥东县| 鄯善县| 托克托县| 湘阴县| 闵行区| 兴仁县| 榆社县| 石台县| 揭西县| 邵阳市| 孟津县| 岑溪市| 波密县| 镇雄县| 韶关市| 石狮市| 温宿县| 祁阳县| 富源县| 沧源| 呼和浩特市|