BlueIce  
          藍色的Java,冰色的BillQian
          日歷
          <2007年7月>
          24252627282930
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234
          統(tǒng)計
          • 隨筆 - 5
          • 文章 - 0
          • 評論 - 5
          • 引用 - 0

          導(dǎo)航

          常用鏈接

          留言簿(2)

          隨筆檔案

          相冊

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

           
            今天在網(wǎng)上看到一篇文章,感覺很好,它講到的是關(guān)于構(gòu)造函數(shù)的作用以及類的構(gòu)造問題,而這是初學(xué)者經(jīng)常會犯甚至是有經(jīng)驗的程序員偶爾也會犯的錯誤,在此我舉例總結(jié)一下,請看下面這段代碼:
            
          public?abstract?class?BaseDlg?extends?JDialog?{
          ????
          public?BaseDlg(Frame?frame,?String?title)?{
          ????????
          super(frame,?title,?true);
          ????????
          this.getContentPane().setLayout(new?BorderLayout());
          ????????
          this.getContentPane().add(createHeadPanel(),?BorderLayout.NORTH);
          ????????
          this.getContentPane().add(createClientPanel(),?BorderLayout.CENTER);
          ????????
          this.getContentPane().add(createButtonPanel(),?BorderLayout.SOUTH);
          ????}


          ????
          private?JPanel?createHeadPanel()?{
          ?????????
          //?創(chuàng)建對話框頭部
          ????}


          ????
          //?創(chuàng)建對話框客戶區(qū)域,交給子類實現(xiàn)
          ????protected?abstract?JPanel?createClientPanel();

          ????
          private?JPanel?createButtonPanel?{
          ?????????
          //?創(chuàng)建按鈕區(qū)域
          ????}

          }


            這個類在有的代碼中工作得很好,但一個同事在使用時,程序卻擲出了一個NullPointerException違例!經(jīng)過比較,找出了工作正常和不正常的程序的細微差別,代碼片斷分別如下:
            一、工作正常的代碼:
                  
          public?class?ChildDlg1?extends?BaseDlg?{
          ????JTextField?jTextFieldName;
          ????
          public?ChildDlg1()?{
          ????????
          super(null,?"Title");
          ????}

          ????
          public?JPanel?createClientPanel()?{
          ????????jTextFieldName?
          =?new?JTextField();
          ????????JPanel?panel?
          =?new?JPanel(new?FlowLayout());
          ????????panel.add(jTextFieldName);
          ?????????
          //?其它代碼
          ????????return?panel;
          ????}

          ????
          }

          ChildDlg1?dlg?
          =?new?ChildDlg1();??//?外部的調(diào)用
           
            二、工作不正常的代碼:
                
          public?class?ChildDlg2?extends?BaseDlg?{
          ????JTextField?jTextFieldName?
          =?new?JTextField();
          ????
          public?ChildDlg2()?{
          ????????
          super(null,?"Title");
          ????}

          ????
          public?JPanel?createClientPanel()?{
          ????????JPanel?panel?
          =?new?JPanel(new?FlowLayout());
          ????????panel.add(jTextFieldName);
          ?????????
          //?其它代碼
          ????????return?panel;
          ????}

          ????
          }

          ChildDlg2?dlg?
          =?new?ChildDlg2();??//?外部的調(diào)用

            你看出來兩段代碼之間的差別了嗎?對了,兩者的差別僅僅在于類變量jTextFieldName的初始化時間。經(jīng)過跟蹤,發(fā)現(xiàn)在執(zhí)行
          panel.add(jTextFieldName)語句之時,jTextFieldName確實是空值.

            當程序創(chuàng)建一個ChildDlg2的實例時,根據(jù)super(null,?“Title”)語句,首先執(zhí)行其父類BaseDlg的構(gòu)造方法;在BaseDlg的構(gòu)造方法中調(diào)用了createClientPanel()方法,這個方法是抽象方法并且被子類ChildDlg2實現(xiàn)了,因此,實際調(diào)用的方法是ChildDlg2中的createClientPanel()方法(因為Java里面采用“動態(tài)綁定”來綁定所有非final的方法);createClientPanel()方法使用了ChildDlg2類的實例變量jTextFieldName,而此時ChildDlg2的變量初始化過程尚未進行,jTextFieldName是null值!所以,ChildDlg2的構(gòu)造過程擲出一個NullPointerException也就不足為奇了。

            再來看ChildDlg1,它的jTextFieldName的初始化代碼寫在了createClientPanel()方法內(nèi)部的開始處,這樣它就能保證在使用之前得到正確的初始化,因此這段代碼工作正常。

          解決問題的兩種方式:

            通過上面的分析過程可以看出,要排除故障,最簡單的方法就是要求項目組成員在繼承使用BaseDlg類,實現(xiàn)createClientPanel()方法時,凡方法內(nèi)部要使用的變量必須首先正確初始化,就象ChildDlg1一樣。然而,把類變量放在類方法內(nèi)初始化是一種很不好的設(shè)計行為,它最適合的地方就是在變量定義塊和構(gòu)造方法中。

            在本文的實例中,引發(fā)錯誤的實質(zhì)并不在ChildDlg2上,而在其父類BaseDlg上,是它在自己的構(gòu)造方法中不適當?shù)卣{(diào)用了一個待實現(xiàn)的抽象方法。

          從概念上講,構(gòu)造方法的職責(zé)是正確初始化類變量,讓對象進入可用狀態(tài)。而BaseDlg卻賦給了構(gòu)造方法額外的職責(zé)。

          本文實例的更好的解決方法是修改BaseDlg類:
            
          public?abstract?class?BaseDlg?extends?JDialog?{
          ????
          public?BaseDlg(Frame?frame,?String?title)?{
          ????????
          super(frame,?title,?true);
          ????????
          this.getContentPane().setLayout(new?BorderLayout());
          ????????
          this.getContentPane().add(createHeadPanel(),?BorderLayout.NORTH);
          ????????
          this.getContentPane().add(createButtonPanel(),?BorderLayout.SOUTH);
          ????}


          ????
          /**?創(chuàng)建對話框?qū)嵗螅仨氄{(diào)用此方法來布局用戶界面
          ?????
          */

          ????
          public?void?initGUI()?{
          ????????
          this.getContentPane().add(createClientPanel(),?BorderLayout.CENTER);
          ????}


          ????
          private?JPanel?createHeadPanel()?{
          ?????????
          //?創(chuàng)建對話框頭部
          ????}


          ????
          //?創(chuàng)建對話框客戶區(qū)域,交給子類實現(xiàn)
          ????protected?abstract?JPanel?createClientPanel();

          ????
          private?JPanel?createButtonPanel?{
          ?????????
          //?創(chuàng)建按鈕區(qū)域
          ????}

          }


          新的BaseDlg類增加了一個initGUI()方法,程序員可以這樣使用這個類:

          ChildDlg?dlg?=?new?ChildDlg();
          dlg.initGUI();
          dlg.setVisible(
          true);

          總結(jié):

            類的構(gòu)造方法的基本目的是正確初始化類變量,不要賦予它過多的職責(zé)。

            設(shè)計類構(gòu)造方法的基本規(guī)則是:用盡可能簡單的方法使對象進入就緒狀態(tài);如果可能,避免調(diào)用任何方法。在構(gòu)造方法內(nèi)唯一能安全調(diào)用的是基類中具有final屬性的方法或者private方法(private方法會被編譯器自動設(shè)置final屬性)。final的方法因為不能被子類覆蓋,所以不會產(chǎn)生問題。
          posted on 2007-03-02 12:58 BillQian 閱讀(369) 評論(3)  編輯  收藏
          評論:
          • # re: 詭秘的Java構(gòu)造問題...  uTsing Posted @ 2007-03-02 13:09
            不錯不錯~
            希望繼續(xù)努力~  回復(fù)  更多評論   

          • # re: 詭秘的Java構(gòu)造問題...  qiuxin1337 Posted @ 2007-03-03 15:50
            挺好的!就是我看不太懂,呵呵!
            好好做吧同志!A ZA!  回復(fù)  更多評論   

          • # re: 詭秘的Java構(gòu)造問題...  itkui Posted @ 2007-07-03 14:32
            雖然現(xiàn)在都學(xué)習(xí)struts、hibernate了。
            可是,Java語言本身理解的還是不透徹。
            哎,只有繼續(xù)了。。。  回復(fù)  更多評論   


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
           
          Copyright © BillQian Powered by: 博客園 模板提供:滬江博客
          主站蜘蛛池模板: 临漳县| 义马市| 甘肃省| 河东区| 姚安县| 渝中区| 改则县| 云南省| 游戏| 寿阳县| 彭泽县| 济阳县| 五莲县| 马鞍山市| 景德镇市| 康平县| 麻阳| 祁连县| 崇信县| 晴隆县| 平潭县| 历史| 梁平县| 海阳市| 尼勒克县| 新化县| 宁海县| 清远市| 邯郸县| 宣城市| 桂林市| 米脂县| 绥中县| 衡阳县| 旬阳县| 酒泉市| 略阳县| 澄城县| 乐山市| 上林县| 漯河市|