?? 通過實例學習java對象的構造過程-java面向對象 - it電子教育門戶 高端java培訓.htm
字號:
...<BR>}<BR>ChildDlg2 dlg = new ChildDlg2(); //
外部的調用<BR>你看出來兩段代碼之間的差別了嗎?對了,兩者的差別僅僅在于類變量jTextFieldName的初始化時間。經過跟蹤,發現在執行panel.add(jTextFieldName)語句之時,jTextFieldName確實是空值。</FONT></P>
<P><FONT
face="Times New Roman">我們知道,Java允許在定義類變量的同時給變量賦初始值。系統運行過程中需要創建一個對象的時候,首先會為對象分配內存空間,然后在“先于調用任何方法之前”根據變量在類內的定義順序來初始化變量,接著再調用類的構造方法。那么,在本例中,為什么在變量定義時便初始化的代碼反而會出現空指針違例呢?</FONT></P>
<P><FONT face="Times New Roman">對象的創建過程和初始化</FONT></P>
<P><FONT
face="Times New Roman">實際上,前面提到的“變量初始化發生在調用任何方法包括構造方法之前”這句話是不確切的,當我們把眼光集中在單個類上時,該說法成立;然而,當把視野擴大到具有繼承關系的兩個或多個類上時,該說法不成立。</FONT></P>
<P><FONT
face="Times New Roman">對象的創建一般有兩種方式,一種是用new操作符,另一種是在一個Class對象上調用newInstance方法;其創建和初始化的實際過程是一樣的:</FONT></P>
<P><FONT
face="Times New Roman">首先為對象分配內存空間,包括其所有父類的可見或不可見的變量的空間,并初始化這些變量為默認值,如int類型為0,boolean類型為false,對象類型為null;</FONT></P>
<P><FONT face="Times New Roman">然后用下述5個步驟來初始化這個新對象:</FONT></P>
<P><FONT
face="Times New Roman">1)分配參數給指定的構造方法;<BR>2)如果這個指定的構造方法的第一個語句是用this指針顯式地調用本類的其它構造方法,則遞歸執行這5個步驟;如果執行過程正常則跳到步驟5;<BR>3)如果構造方法的第一個語句沒有顯式調用本類的其它構造方法,并且本類不是Object類(Object是所有其它類的祖先),則調用顯式(用super指針)或隱式地指定的父類的構造方法,遞歸執行這5個步驟;如果執行過程正常則跳到步驟5;<BR>4)按照變量在類內的定義順序來初始化本類的變量,如果執行過程正常則跳到步驟5;<BR>5)執行這個構造方法中余下的語句,如果執行過程正常則過程結束。</FONT></P>
<P><FONT
face="Times New Roman">這一過程可以從下面的時序圖中獲得更清晰的認識:<BR> </FONT></P>
<P><FONT
face="Times New Roman">對分析本文的實例最重要的,用一句話說,就是“父類的構造方法調用發生在子類的變量初始化之前”??梢杂孟旅娴睦觼碜C明:</FONT></P>
<P><FONT face="Times New Roman">// Petstore.java<BR>class
Animal {<BR> Animal()
{<BR>
System.out.println("Animal");<BR>
}<BR>}<BR>class Cat extends Animal {<BR>
Cat() {<BR>
System.out.println("Cat");<BR>
}<BR>}<BR>class Store {<BR> Store()
{<BR>
System.out.println("Store");<BR>
}<BR>}<BR>public class Petstore extends
Store{<BR> Cat cat = new
Cat();<BR> Petstore()
{<BR>
System.out.println("Petstore");<BR>
}<BR> public static void main(String[] args)
{<BR> new
Petstore();<BR>
}<BR>}<BR>運行這段代碼,它的執行結果如下:</FONT></P>
<P><FONT
face="Times New Roman">Store<BR>Animal<BR>Cat<BR>Petstore<BR>從結果中可以看出,在創建一個Petstore類的實例時,首先調用了它的父類Store的構造方法;然后試圖創建并初始化變量cat;在創建cat時,首先調用了Cat類的父類Animal的構造方法;其后才是Cat的構造方法主體,最后才是Petstore類的構造方法的主體。</FONT></P>
<P><FONT face="Times New Roman">尋找程序產生例外的原因</FONT></P>
<P><FONT
face="Times New Roman">現在回到本文開始提到的實例中來,當程序創建一個ChildDlg2的實例時,根據super(null,
“Title”)語句,首先執行其父類BaseDlg的構造方法;在BaseDlg的構造方法中調用了createClientPanel()方法,這個方法是抽象方法并且被子類ChildDlg2實現了,因此,實際調用的方法是ChildDlg2中的createClientPanel()方法(因為Java里面采用“動態綁定”來綁定所有非final的方法);createClientPanel()方法使用了ChildDlg2類的實例變量jTextFieldName,而此時ChildDlg2的變量初始化過程尚未進行,jTextFieldName是null值!所以,ChildDlg2的構造過程擲出一個NullPointerException也就不足為奇了。</FONT></P>
<P><FONT
face="Times New Roman">再來看ChildDlg1,它的jTextFieldName的初始化代碼寫在了createClientPanel()方法內部的開始處,這樣它就能保證在使用之前得到正確的初始化,因此這段代碼工作正常。</FONT></P>
<P><FONT face="Times New Roman">解決問題的兩種方式</FONT></P>
<P><FONT
face="Times New Roman">通過上面的分析過程可以看出,要排除故障,最簡單的方法就是要求項目組成員在繼承使用BaseDlg類,實現createClientPanel()方法時,凡方法內部要使用的變量必須首先正確初始化,就象ChildDlg1一樣。然而,把類變量放在類方法內初始化是一種很不好的設計行為,它最適合的地方就是在變量定義塊和構造方法中。</FONT></P>
<P><FONT
face="Times New Roman">在本文的實例中,引發錯誤的實質并不在ChildDlg2上,而在其父類BaseDlg上,是它在自己的構造方法中不適當地調用了一個待實現的抽象方法。</FONT></P>
<P><FONT
face="Times New Roman">從概念上講,構造方法的職責是正確初始化類變量,讓對象進入可用狀態。而BaseDlg卻賦給了構造方法額外的職責。</FONT></P>
<P><FONT
face="Times New Roman">本文實例的更好的解決方法是修改BaseDlg類:</FONT></P>
<P><FONT face="Times New Roman">public abstract class BaseDlg
extends JDialog {<BR> public BaseDlg(Frame
frame, String title)
{<BR> super(frame,
title, true);<BR>
this.getContentPane().setLayout(new
BorderLayout());<BR>
this.getContentPane().add(createHeadPanel(),
BorderLayout.NORTH);<BR>
this.getContentPane().add(createButtonPanel(),
BorderLayout.SOUTH);<BR> }</FONT></P>
<P><FONT face="Times New Roman"> /**
創建對話框實例后,必須調用此方法來布局用戶界面<BR>
*/<BR> public void initGUI()
{<BR>
this.getContentPane().add(createClientPanel(),
BorderLayout.CENTER);<BR> }</FONT></P>
<P><FONT face="Times New Roman"> private
JPanel createHeadPanel()
{<BR> ... //
創建對話框頭部<BR> }</FONT></P>
<P><FONT face="Times New Roman"> //
創建對話框客戶區域,交給子類實現<BR> protected abstract
JPanel createClientPanel();</FONT></P>
<P><FONT face="Times New Roman"> private
JPanel createButtonPanel
{<BR> ... //
創建按鈕區域<BR>
}<BR>}<BR>新的BaseDlg類增加了一個initGUI()方法,程序員可以這樣使用這個類:</FONT></P>
<P><FONT face="Times New Roman">ChildDlg dlg = new
ChildDlg();<BR>dlg.initGUI();<BR>dlg.setVisible(true);<BR>總結</FONT></P>
<P><FONT
face="Times New Roman">類的構造方法的基本目的是正確初始化類變量,不要賦予它過多的職責。</FONT></P>
<P><FONT
face="Times New Roman">設計類構造方法的基本規則是:用盡可能簡單的方法使對象進入就緒狀態;如果可能,避免調用任何方法。在構造方法內唯一能安全調用的是基類中具有final屬性的方法或者private方法(private方法會被編譯器自動設置final屬性)。final的方法因為不能被子類覆蓋,所以不會產生問題。</FONT></P></DIV></SPAN></TD></TR>
<TR>
<TD width="71%"> </TD>
<TD width="29%">【 <A
href="http://www.mldn.cn/print.jtml?articleid=2618">打印</A> 】【
<A
href="http://www.mldn.cn/member/favlist.jtml?action=add&postid=2618">收藏</A>
】【 <A href="http://www.mldn.cn/email.jtml?articleid=2618"
target=_blank>推薦</A> 】 </TD></TR>
<TR>
<TD colSpan=2>
<TABLE cellSpacing=3 cellPadding=0 width="100%" align=center
bgColor=#ffffff border=0>
<TBODY>
<TR height=25>
<TD align=middle width="33%"><IMG height=95 alt=java視頻教程
src="通過實例學習Java對象的構造過程-JAVA面向對象 - IT電子教育門戶 高端JAVA培訓.files/javavideo.gif"
width=642></TD></TR>
<TR>
<TD class=content-table vAlign=top align=middle>
<TABLE>
<TBODY>
<TR>
<TD>
<TABLE>
<TBODY>
<TR>
<TD><A
href="http://www.mldn.cn/articleview/2007-8-21/article_view_2251.htm"
rel=external><IMG class=midImg alt=struts2.0入門視頻
src="通過實例學習Java對象的構造過程-JAVA面向對象 - IT電子教育門戶 高端JAVA培訓.files/struts2.gif"
width=90></A></TD></TR>
<TR>
<TD style="HEIGHT: 22px"> <A
title=struts2.0入門視頻
href="http://www.mldn.cn/articleview/2007-8-21/article_view_2251.htm"
rel=external>struts2.0入門視頻</A></TD></TR></TBODY></TABLE></TD>
<TD>
<TABLE>
<TBODY>
<TR>
<TD><A
href="http://www.mldn.cn/articleview/2007-6-15/article_view_2141.htm"
rel=external><IMG class=midImg
alt=JAVAEE學習流程和學習方法
src="通過實例學習Java對象的構造過程-JAVA面向對象 - IT電子教育門戶 高端JAVA培訓.files/j2eejc.gif"
width=90></A></TD></TR>
<TR>
<TD style="HEIGHT: 22px"> <A
title=JAVAEE學習流程和學習方法
href="http://www.mldn.cn/articleview/2007-6-15/article_view_2141.htm"
rel=external>JAVAEE學習流程和學習方..</A></TD></TR></TBODY></TABLE></TD>
<TD>
<TABLE>
<TBODY>
<TR>
<TD><A
href="http://www.mldn.cn/articleview/2007-6-5/article_view_2091.htm"
rel=external><IMG class=midImg
alt=1-Java介紹及JDK配置
src="通過實例學習Java對象的構造過程-JAVA面向對象 - IT電子教育門戶 高端JAVA培訓.files/javase.gif"
width=90></A></TD></TR>
<TR>
<TD style="HEIGHT: 22px"> <A
title=1-Java介紹及JDK配置
href="http://www.mldn.cn/articleview/2007-6-5/article_view_2091.htm"
rel=external>1-Java介紹及JDK配置..</A></TD></TR></TBODY></TABLE></TD>
<TD>
<TABLE>
<TBODY>
<TR>
<TD><A
href="http://www.mldn.cn/articleview/2007-4-19/article_view_2012.htm"
rel=external><IMG class=midImg alt=Oracle中的多表連接
src="通過實例學習Java對象的構造過程-JAVA面向對象 - IT電子教育門戶 高端JAVA培訓.files/Oracle.gif"
width=90></A></TD></TR>
<TR>
<TD style="HEIGHT: 22px"> <A
title=Oracle中的多表連接
href="http://www.mldn.cn/articleview/2007-4-19/article_view_2012.htm"
rel=external>Oracle中的多表連接</A></TD></TR></TBODY></TABLE></TD>
<TD>
<TABLE>
<TBODY>
<TR>
<TD><A
href="http://www.mldn.cn/articleview/2007-4-11/article_view_1978.htm"
rel=external><IMG class=midImg
alt=Struts中logic標簽的使用
src="通過實例學習Java對象的構造過程-JAVA面向對象 - IT電子教育門戶 高端JAVA培訓.files/struts.gif"
width=90></A></TD></TR>
<TR>
<TD style="HEIGHT: 22px"> <A
title=Struts中logic標簽的使用
href="http://www.mldn.cn/articleview/2007-4-11/article_view_1978.htm"
rel=external>Struts中logic標簽..</A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD colSpan=2>
<TABLE cellSpacing=3 cellPadding=0 width="100%" align=center
bgColor=#ffffff border=0>
<TBODY>
<TR height=25>
<TD align=middle width="33%" bgColor=#aac4c4><FONT
color=#ffffff>相關文章</FONT></TD>
<TD align=middle width="33%" bgColor=#aac4c4><FONT
color=#ffffff>推薦文章</FONT></TD></TR>
<TR>
<TD class=content-table vAlign=top>
<TABLE>
<TBODY>
<TR>
<TD><A
href="http://www.mldn.cn/articleview/2007-11-7/article_view_2650.htm"
rel=external>垃圾收集器與Java程序的性能</A> <IMG
alt=24小時內新文章
src="通過實例學習Java對象的構造過程-JAVA面向對象 - IT電子教育門戶 高端JAVA培訓.files/new.gif"
align=absMiddle border=0></TD>
<TD style="TEXT-ALIGN: right"><SPAN
class=link-Date>[11.7]</SPAN></TD></TR>
<TR>
<TD><A
href="http://www.mldn.cn/articleview/2007-11-7/article_view_2652.htm"
rel=external>詳細解析Java中抽象類和接口的..</A> <IMG
alt=24小時內新文章
src="通過實例學習Java對象的構造過程-JAVA面向對象 - IT電子教育門戶 高端JAVA培訓.files/new.gif"
align=absMiddle border=0></TD>
<TD style="TEXT-ALIGN: right"><SPAN
class=link-Date>[11.7]</SPAN></TD></TR>
<TR>
<TD><A
href="http://www.mldn.cn/articleview/2007-11-2/article_view_2624.htm"
rel=external>講述java語言中內部類的研究</A></TD>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -