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

當前位置:首頁>>開發(fā)編程>>JAVA>>新聞內容
全世界所有程序員都會犯的錯誤
作者:蔡學鏞 發(fā)布時間: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);
  }
}

執(zhí)行結果是:
obj.counter1==1
obj.counter2==0

你有沒有被此結果嚇一跳?乍看程序代碼,你很可能會認為counter1和counter2的值一定會相等,但執(zhí)行結果顯然不是如此。其實,程序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執(zhí)行完,回到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
發(fā)表日期:03/10/2003


最新更新
·Java開發(fā)技術十年的回顧與展
·關于TOMCAT主目錄與虛擬目錄
·用java程序調用ffmpeg執(zhí)行視
·JavaBean與Enterprise JavaB
·Java開發(fā)人員的十大戒律
·JavaFX Script將終結AJAX?還
·解決IE中所有png圖片透明問題
·JSP解決地址欄中傳遞中文字符
·Eclipse五歲了:Java程序員的
·審查Java代碼的十一種常見錯
相關信息
放生
愚愛
夠愛
觸電
白狐
心跳
知足
犯錯
降臨
分愛
葬愛
光榮
畫心
火花
稻香
愛得起
這種愛
大丈夫
花蝴蝶
二缺一
小酒窩
下雨天
右手邊
安靜了
棉花糖
明天過后
邊做邊愛
擦肩而過
沒有如果
懷念過去
等一分鐘
越來越愛
寂寞暴走
你的承諾
Nobody
我們都一樣
永遠在身邊
天使的翅膀
原諒我一次
i miss you
原諒我一次
吻的太逼真
姑娘我愛你
做你的愛人
一定要愛你
飛向別人的床
愛上別人的人
感動天感動地
心在跳情在燒
不潮不用花錢
如何能把你忘記
即使知道要見面
愛上你是一個錯
最后一次的溫柔
愛上你是我的錯
怎么會狠心傷害我
親愛的那不是愛情
傷心時候可以聽情歌
愛上你等于愛上了錯
不是因為寂寞才想你
主站蜘蛛池模板: 武冈市| 隆安县| 泾川县| 巴楚县| 镇平县| 巴青县| 东城区| 南昌市| 安平县| 南昌市| 洛宁县| 桑日县| 汉源县| 家居| 精河县| 鄱阳县| 阳高县| 黑山县| 区。| 九江市| 南皮县| 屯门区| 从化市| 故城县| 麻城市| 甘孜县| 松桃| 陆丰市| 渝北区| 西乌| 中牟县| 安化县| 德阳市| 宜宾市| 娄底市| 河西区| 大化| 区。| 田阳县| 锡林浩特市| 安泽县|