BlueIce  
蓝色的Java,冰色的BillQian
日历
<2007年7月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234
统计
  • 随笔 - 5
  • 文章 - 0
  • 评论 - 5
  • 引用 - 0

导航

常用链接

留言簿(2)

随笔档案

相册

搜索

  •  

最新评论

阅读排行榜

评论排行榜

 
  今天在网上看到一篇文章,感觉很好,它讲到的是关于构造函数的作用以及类的构造问题,而这是初学者经常会犯甚至是有经验的程序员偶尔也会犯的错误,在此我举例总结一下,请看下面这段代码:
  
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() {
         
// 创建对话框头部
    }


    
// 创建对话框客户区域,交给子类实现
    protected abstract JPanel createClientPanel();

    
private JPanel createButtonPanel {
         
// 创建按钮区域
    }

}


  这个类在有的代码中工作得很好,但一个同事在使用时,程序却掷出了一个NullPointerException违例!经过比较,找出了工作正常和不正常的程序的细微差别,代码片断分别如下:
  一、工作正常的代码:
        
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();  // 外部的调用
 
  二、工作不正常的代码:
      
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();  // 外部的调用

  你看出来两段代码之间的差别了吗?对了,两者的差别仅仅在于类变量jTextFieldName的初始化时间。经过跟踪,发现在执行
panel.add(jTextFieldName)语句之时,jTextFieldName确实是空值.

  当程序创建一个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的方法因为不能被子类覆盖,所以不会产生问题。
posted on 2007-03-02 12:58 BillQian 阅读(363) 评论(3)  编辑  收藏
评论:
  • # re: 诡秘的Java构造问题...  uTsing Posted @ 2007-03-02 13:09
    不错不错~
    希望继续努力~  回复  更多评论   

  • # re: 诡秘的Java构造问题...  qiuxin1337 Posted @ 2007-03-03 15:50
    挺好的!就是我看不太懂,呵呵!
    好好做吧同志!A ZA!  回复  更多评论   

  • # re: 诡秘的Java构造问题...  itkui Posted @ 2007-07-03 14:32
    虽然现在都学习struts、hibernate了。
    可是,Java语言本身理解的还是不透彻。
    哎,只有继续了。。。  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 
 
Copyright © BillQian Powered by: 博客园 模板提供:沪江博客