Java中继承关系的构造函数的调用顺序

来源:互联网 发布:2017年java就业前景 编辑:程序博客网 时间:2024/06/06 02:34

情况一:在JAVA中,我们通常把C中的函数叫做方法。对于子类调用父类的构造方法可以做出如下解释: 子类无条件地继承父类的不含参数的构造方法。如果一个类中没有构造函数的话编译器会默认为该类创建一个无参空构造器
    如果子类自己没有构造方法,则它将继承父类的无参数构造方法作为自己的构造方法;

下面用一个例子验证下

public class Demo03 {
public static void main(String[] args) {
new Child_2();
}
}

class Parent {
public Parent() {
System.out.println("Parent()");
}
}
class Child_2 extends Parent {
}

输出的结果如下


可以看出子类虽然没有构造方法,但还是默认继承了父类的构造方法

情况2:

如果子类自己定义了构造方法,则在创建新对象时,它将先执行继承自父类的无参数构造方法,然后再执行自己的构造方法。

public class Demo03 {
public static void main(String[] args) {
new Child(3);
}
}
class Parent {
public Parent() {
System.out.println("Parent()");
}
}
class Child extends Parent {
private int num;
// 调用子类的构造函数的时候默认先调用父类的无参构造函数
public Child(int value) {
this.num = value;
System.out.println("Child()自己的构造方法执行:" + "num = " + this.num);
}
}

构造函数调用的顺序是:Child(int value)->Parent(),构造函数的执行顺序是Parent()->Child(int value)

输出的结果:


我们再修改一点来看看,加入将Child类稍微改一下

class Child extends Parent {
private int num = 4;


// 调用子类的构造函数的时候默认先调用父类的无参构造函数
public Child(int value) {
this.num = value;
System.out.println("Child()自己的构造方法执行:" + "num = " + this.num);
}
}

这时候程序的运行过程会稍稍不同,当调用完父类的午餐构造函数之后并不立即执行this.num = value;这句,而是想执行private int num = 4;这一句,我们从设计者的角度来看这很合理,因为假如我们在构造函数中需要使用到Child的属性的话,属性已经再外面初始化了,如果不先执行成员变量的初始化的话就会造成空指针等异常。

所以Child中的执行顺序是 private int num = 4;——>this.num = value;——>System.out.println("Child()自己的构造方法执行:" + "num = " + this.num);


   情况3:对于父类含参数的构造方法,子类可以通过在自己的构造方法中使用 super 关键字来调用它,但这个调用语句必须是子类构造方法的第一个可执行语句

public class Demo04 {
public static void main(String[] args) {
new Child_1();
}
}
class Child_1 extends Parent_1 {
public Child_1() {
super(3);
System.out.println("Child_1()");
}
}
class Parent_1 {
private int num;
public Parent_1() {
System.out.println("Parent_1()");
}
public Parent_1(int value) {
this.num = value;
System.out.println("Parent_1(int value)" + ":num = " + num);
}
}

输出的结果是


可以看出,这里并没用再去默认调用父类的无参构造方法,而是通过super调用public Parent_1(int value) 这个带参构造方法


综合一个案例分析下:

public class Sanwich extends Lunch {
private Bread b = new Bread();
public Sanwich() {
System.out.println("Sanwich");
}
public static void main(String[] args) {
new Sanwich();
}
}
class Meal {
public Meal() {
System.out.println("Meal()");
}
}
class Bread {
public Bread() {
System.out.println("Bread()");
}
}
class Lunch extends Meal {
public Lunch() {
System.out.println("Lunch()");
}

}

输出结果为

程序的构造器调用顺序是这样的:Sanwich() ->Lunch() -> Meal()->Bread();输出的顺序就是Meal()->Lunch()->Bread()->Sanwich(),结合上面的分析就可以理解了


0 0