通过实例学习java对象的构造过程-java面向对象 - it电子教育门户 高端java培训.htm
来自「这是我自己认真整理的java面向对象的各个方面的知识.想和大家一起来分享我的快乐」· HTM 代码 · 共 658 行 · 第 1/3 页
HTM
658 行
...<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">对分析本文的实例最重要的,用一句话说,就是“父类的构造方法调用发生在子类的变量初始化之前”。可以用下面的例子来证明:</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 + =
减小字号Ctrl + -
显示快捷键?