Java中创建子类对象的执行流程分析

作者:冯老师,华清远见教育科技集团讲师。

一、影响创建子类对象的几个因素

Java中创建一个子类对象时,执行流程比较复杂,主要是由于构造器的重载、this关键字的使用、初始化块、继承及super关键字的存在。下面对这几个因素做个简单介绍。

1.方法的重载

Java中允许方法的重载,即同一个类中方法名相同,但参数个数不同或参数的类型不同。除了普通的类方法外,构造器也允许重载。且通过this关键字可以使类的构造器互相调用。

2.this关键字

在构造器中的this关键字,指该构造器所创建的新对象,在方法中的构造器关键字,指调用该方法的对象。使用this关键字,主要是下面三种场合:

在类的内部方法或构造器中引用该类的实例变量和方法;将当前对象作为参数传递给其它方法或构造器;用来调用其他的重载的构造器

3.初始化块

Java中允许类中定义初始化块,即类中的“游离块”——不属于变量声明、不属于方法、不属于构造器,但需要用{}单独括起来。不管使用哪个构造器创建对象,它都会被首先运行,然后才是构造器的主体部分被执行

二、创建子类对象的执行流程

创建一个类对象时,执行流程如下:

1.设置实例变量的值为缺省的初始值

2.调用对象的构造器,绑定构造器参数。

3.如果构造器中有this()调用,则根据this()调用的参数调用相应的重载构造器,然后,转到步骤5;否则转到步骤4。

4. 除java.lang.Object类外,调用父类的中的初始化块初始化父类的属性,然后调用父类构造器,如果在构造器中有super()调用,则根据super()中的参数调用父类中相应的构造器。

5.使用初始化程序和初始化块初始化成员。

6.执行构造器方法体中其他语句。

三、代码演示

下面通过一个例子,来演示上述流程。

1.工程结构如下:

2.工程中涉及的Java源文件如下:

1)包com.person下的父类Person的代码如下:

//------------Person.java---------------
  package com.person;
  public class Person {
  String name = "zhangsan";
  String gender = "male";
  int age = 200;
  public Person() {
  System.out.println("Person()");
  }
  public Person(String newName) {
  name = newName;
  System.out.println("Person(String newName)");
  System.out.println("name=" + name + " age=" + age + " gender=" + gender);
  }
  public Person(String newName, int newAge) {
  name = newName;
  age = newAge;
  System.out.println("Person(String newName, int newAge)");
  System.out.println("name=" + name + " age=" + age + " gender=" + gender);
  }
  {
  gender = "male";
  age = 50;
  System.out.println("Person initialize:" + "name=" + name + " age=" + age + " gender=" + gender);
  }
  }

2)包com.person下的Person的子类Teacher的代码如下:

//---------------Teacher.java---------------
  package com.person;
  public class Teacher extends Person{
  String department = "HR";
  int schoolage = 100;
  public Teacher() {
  System.out.println("Teacher()");
  }
  public Teacher(String newName) {
  super(newName);
  System.out.println("Teacher(String newName)");
  }
  public Teacher(int schoolage) {
  this.schoolage = schoolage;
  System.out.println("Teacher(int schoolage)");
  }
  public Teacher(String newName, int newAge) {
  super(newName, newAge);
  System.out.println("Teacher(String newName, int newAge)");
  }
  public Teacher(int schoolage, String department) {
  this(schoolage);
  this.department = department;
  System.out.println("Teacher(int schoolage, String department)");
  }
  {
  age = 66;
  System.out.println("Teacher initialize:" + "name=" + name + " age=" + age + " gender=" + gender);
  }
  }

3)包com.person下的main函数代码如下:

//-----------Demo.java------------
  package com.person;
  public class Demo {
  public static void main(String[] args) {
  Teacher t1 = new Teacher();
  System.out.println("---------------------------");
  Teacher t2 = new Teacher("Tom");
  System.out.println("---------------------------");
  Teacher t3 = new Teacher(10);
  System.out.println("---------------------------");
  Teacher t4 = new Teacher("Jerry", 35);
  System.out.println("---------------------------");
  Teacher t5 = new Teacher(20, "教学部");
  System.out.println("---------------------------");
  }
  }

程序的执行结果如下:

Person initialize:name=zhangsan age=50 gender=male
  Person()
  Teacher initialize:name=zhangsan age=66 gender=male department=HR age=66
  Teacher()
  ---------------------------
  Person initialize:name=zhangsan age=50 gender=male
  Person(String newName)
  name=Tom age=50 gender=male
  Teacher initialize:name=Tom age=66 gender=male department=HR age=66
  Teacher(String newName)
  ---------------------------
  Person initialize:name=zhangsan age=50 gender=male
  Person()
  Teacher initialize:name=zhangsan age=66 gender=male department=HR age=66
  Teacher(int schoolage)
  ---------------------------
  Person initialize:name=zhangsan age=50 gender=male
  Person(String newName, int newAge)
  name=Jerry age=35 gender=male
  Teacher initialize:name=Jerry age=66 gender=male department=HR age=66
  Teacher(String newName, int newAge)
  ---------------------------
  Person initialize:name=zhangsan age=50 gender=male
  Person()
  Teacher initialize:name=zhangsan age=66 gender=male department=HR age=66
  Teacher(int schoolage)
  Teacher(int schoolage, String department)
  ---------------------------

四、总结分析

通过观察上面的执行结果,可以看出,在创建子类对象时,一定会先设置父类实例变量的值为缺省的初始值 ,再调用父类的初始化块,然后是调用父类一个匹配构造器。接下来是,调用子类实例变量的值为缺省初始值,调用子类的初始化块,好是子类的构造器。