通过实例学习Java对象的构造过程

欢迎进入Java社区论坛,与200万技术人员互动交流 >>进入

  对分析本文的实例最重要的,用一句话说,就是“父类的构造方法调用发生在子类的变量初始化之前”。可以用下面的例子来证明:

// Petstore.javaclass Animal { Animal() {  System.out.println(“Animal”); }}class Cat extends Animal { Cat() {  System.out.println(“Cat”); }}class Store { Store() {  System.out.println(“Store”); }}public class Petstore extends Store{ Cat cat = new Cat(); Petstore() {  System.out.println(“Petstore”); } public static void main(String[] args) {  new Petstore(); }}   运行这段代码,它的执行结果如下:  Store  Animal  Cat  Petstore  从结果中可以看出,在创建一个Petstore类的实例时,首先调用了它的父类Store的构造方法;然后试图创建并初始化变量cat;在创建cat时,首先调用了Cat类的父类Animal的构造方法;其后才是Cat的构造方法主体,最后才是Petstore类的构造方法的主体。  寻找程序产生例外的原因  现在回到本文开始提到的实例中来,当程序创建一个ChildDlg2的实例时,根据super(null, “Title”)语句,首先执行其父类BaseDlg的构造方法;在BaseDlg的构造方法中调用了createClientPanel()方法,这个方法是抽象方法并且被子类ChildDlg2实现了,因此,实际调用的方法是ChildDlg2中的createClientPanel()方法(因为Java里面采用“动态绑定”来绑定所有非final的方法);createClientPanel()方法使用了ChildDlg2类的实例变量jTextFieldName,而此时ChildDlg2的变量初始化过程尚未进行,jTextFieldName是null值!所以,ChildDlg2的构造过程掷出一个NullPointerException也就不足为奇了。  再来看ChildDlg1,它的jTextFieldName的初始化代码写在了createClientPanel()方法内部的开始处,这样它就能保证在使用之前得到正确的初始化,因此这段代码工作正常。  解决问题的两种方式  通过上面的分析过程可以看出,要排除故障,最简单的方法就是要求项目组成员在继承使用BaseDlg类,实现createClientPanel()方法时,凡方法内部要使用的变量必须首先正确初始化,就象ChildDlg1一样。然而,把类变量放在类方法内初始化是一种很不好的设计行为,它最适合的地方就是在变量定义块和构造方法中。  在本文的实例中,引发错误的实质并不在ChildDlg2上,而在其父类BaseDlg上,是它在自己的构造方法中不适当地调用了一个待实现的抽象方法。  从概念上讲,构造方法的职责是正确初始化类变量,让对象进入可用状态。而BaseDlg却赋给了构造方法额外的职责。  本文实例的更好的解决方法是修改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); } /** 创建对话框实例后,必须调用此方法来布局用户界面 */ public void initGUI() {  this.getContentPane().add(createClientPanel(), BorderLayout.CENTER); } private JPanel createHeadPanel() {  … // 创建对话框头部 } // 创建对话框客户区域,交给子类实现 protected abstract JPanel createClientPanel(); private JPanel createButtonPanel {  … // 创建按钮区域 }}   新的BaseDlg类增加了一个initGUI()方法,程序员可以这样使用这个类: ChildDlg dlg = new ChildDlg();dlg.initGUI();dlg.setVisible(true);   总结  类的构造方法的基本目的是正确初始化类变量,不要赋予它过多的职责。  设计类构造方法的基本规则是:用尽可能简单的方法使对象进入就绪状态;如果可能,避免调用任何方法。在构造方法内唯一能安全调用的是基类中具有final属性的方法或者private方法(private方法会被编译器自动设置final属性)。final的方法因为不能被子类覆盖,所以不会产生问题。

[1][2]

为了一些琐事吵架,然后冷战,疯狂思念对方,最后和好。

通过实例学习Java对象的构造过程

相关文章:

你感兴趣的文章:

标签云: