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

本文提供一个项目中的错误实例,提供对其观察和分析,揭示出Java语言实例化一个对象具体过程,最后总结出设计Java类的一个重要规则。通过阅读本文,可以使Java程序员理解Java对象的构造过程,从而设计出更加健壮的代码。本文适合Java初学者和需要提高的Java程序员阅读。

程序掷出了一个异常

作者曾经在一个项目里面向项目组成员提供了一个抽象的对话框基类,使用者只需在子类中实现基类的一个抽象方法来画出显示数据的界面,就可使项目内的对话框具有相同的风格。具体的代码实现片断如下(为了简洁起见,省略了其他无关的代码):

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(frame, "Title"); // 外部的调用

二、工作不正常的代码:

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确实是空值。

我们知道,Java允许在定义类变量的同时给变量赋初始值。系统运行过程中需要创建一个对象的时候,首先会为对象分配内存空间,然后在“先于调用任何方法之前”根据变量在类内的定义顺序来初始化变量,接着再调用类的构造方法。那么,在本例中,为什么在变量定义时便初始化的代码反而会出现空指针违例呢?

时间: 2024-09-29 09:26:34

通过实例学习Java对象的构造过程的相关文章

JVM源码分析之Java对象的创建过程

本文将基于HotSpot实现对Java对象的创建过程进行深入分析. 定义两个简单的类AAA和BBB 通过"javap -c AAA"`查看编译之后的字节码,具体如下: Java中的new关键字对应jvm中的new指令,定义在InterpreterRuntime类中,实现如下: new指令的实现过程: 1.其中pool是AAA的constant pool,此时AAA的class已经加载到虚拟机中,new指令后面的#2表示BBB类全限定名的符号引用在constant pool的位置: 2.

深入解析Java对象的初始化过程

我们先来看这道面试题: public class Base{ private String baseName = "base"; //构造方法 public Base(){callName();}   //对象方法 public void callName(){ System. out. println(baseName); } //静态内部类    static class Sub extends Base{ //静态内部类的字段 private String baseName = 

Java和Ceylon对象的构造和验证_java

当变换Java代码为Ceylon代码时,有时候我会遇到一些Java类构造器混淆了验证与初始化的情形.让我们使用一个简单但是人为的代码例子来说明我想阐述的意思. 一些坏代码 考虑下面的Java类.(伙计,不要在家里写这样的代码) public class Period { private final Date startDate; private final Date endDate; //returns null if the given String //does not represent

XML的操作——JAXB进行Java对象和XML之间的转换

JAXB(Java Architecture for XML Binding)是一种特殊的序列化/反序列化工具,可实现Java对象与XML的相互转换. 在JAXB中将一个Java对象-->XML的过程称之为Marshal,XML-->Java对象的过程称之为UnMarshal. @XmlRootElement public class SClass {private String cnum;private List<Student> students;public SClass()

讲解Java中如何构造内部类对象以及访问对象_IOS

通过反射构造内部类对象 首先在 javalang 包下写一个包含内部类的类: package javalang; public class Outer { public static class Inner1{} } 注意这个类是 public static,后面我们慢慢把这些修饰符去掉. 要想通过反射来创建 Inner1 对象,首先要获得 Inner1 的 Class 对象.我们在 Outer 中写上 main 方法: public class Outer { public static cl

深入分析java中类的构造

概要:本文通过查看一个精心构造的类结构的运行输出和使用javap工具查看实际生成的java字节码(bytecode)向java程序员展示了一个类在运行时是如何构造生成的. 关键字: java 构造 javap 字节码 bytecode 按照java规范,一个类实例的构造过程是遵循以下顺序的: 1.如果构造方法(constructor,也有翻译为构造器和构造函数的)是有参数的则进行参数绑定. 2.内存分配将非静态成员赋予初始值(原始类型的成员的值为规定值,例如int型为0,float型为0.0f,

Java对象序列化使用基础

所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象.这个过程也可以通过网络实现,可以先在Windows机器上创建一个对象,对其序列化,然后通过网络发给一台Unix机器,然后在那里准确无误地重新"装配".像RMI.Socket.JMS.EJB它们中的一种,彼此为什么能够传递Java对象,当然都是对象序列化机制的功劳. Java对象序列化机制一般来讲有两种用途: Java的JavaBeans: Bean的状态信息通常是在设计时配置的,Bean的状态信息必须被

Java 对象序列化机制详解

对象序列化的目标:将对象保存到磁盘中,或允许在网络中直接传输对象. 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久的保存在磁盘上,通过网络将这种二进制流传输到另一个网络节点.其他程序一旦获得了这种二进制流,都可以讲这种二进制流恢复成原来的Java对象.   如果需要让某个对象支持序列化机制,则必须让它的类是可序列化的,则这个类必须实现如下两个接口之一: · Serializable · Externalizable Serializable是一个标志

Java:对象的强、软、弱和虚引用

1.对象的强.软.弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期.这4种级别由高到低依次为:强引用.软引用.弱引用和虚引用.图1为对象应用类层次.   图1 ⑴强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.当内