父类的构造方法不能被子类继承。假定Base父类有以下构造方法:

public Base(Srting msg){
  this.msg=msg;
}

以下Sub类继承了Base类:

public class Sub extends Base{}

以上Sub类有一个隐含的默认构造方法,形式如下:

public Sub(){}

尽管在Base父类中定义了如下形式的构造方法:

public Base(String msg)

但Sub类不会继承Base类的构造方法,因此以下代码是不合法的:

//非法,Sub类不存在这样的构造方法
Sub b=new Sub("Hello");

在子类的构造方法中,可以通过super语句调用父类的构造方法。例如:

public class Sub extends Base{
  public Sub(){
    //调用Base父类的Base(String msg)构造方法
    super("Hello");
  }

  public Sub(String msg){
    //调用Base父类的Base(String msg)构造方法
    super(msg);
  } 
}

假如在子类的构造方法中有super语句,它必须作为构造方法的第一条语句(不考虑注释语句),以下代码是非法的:

public Sub(){
  String msg= "Hello";
  super(msg);       //非法,super语句必须作为构造方法的第一条语句
}

在通过new语句创建子类的实例时,Java虚拟机首先执行父类的构造方法,再执行子类的构造方法。在多级继承的情况下,将从继承树的最上层的父类开始,依次执行各个类的构造方法。

探秘Java语言中子类调用父类的构造方法的方式_构造方法

大力向卫琴请教创建子类对象,先调用父类构造方法的意义

探秘Java语言中子类调用父类的构造方法的方式_java_02

创建子类实例时,先调用父类构造方法,再调用子类构造方法

在例程1的Base.java和Sub.java中,Base父类和Sub子类分别有一个实例变量a和b,当创建Sub类的实例时,这两个实例变量都会被初始化。

例程1 Base.java和Sub.java

/** Base.java */
package mypack4;
public class Base{
  int a;
  public Base(int a){ this.a=a;}
}

/** Sub.java */
package mypack4;
public class Sub extends Base{
  int b;
  public Sub(int a,int b){
    super(a);                          //初始化父类的实例变量a
    this.b=b;                          //初始化子类的实例变量b
  }
  
  public static void main(String args[]){
    Sub sub=new Sub(1,2);
    System.out.println(sub.a+","+sub.b);       //打印1,2
  }
}

大力:“如果子类的构造方法没有通过super语句调用父类的构造方法,那会怎么样呢?”

卫琴姐:“此时Java虚拟机会自动先调用父类的不带参数的构造方法。”

在例程2的Base.java和Sub.java中,Base类有一个不带参数的构造方法。Sub类的Sub(int i)构造方法没有用super语句调用父类的构造方法,因此当创建Sub类的实例时,会先自动调用Base父类的不带参数的构造方法。

例程2 Base.java和Sub.java

/** Base.java */
package mypack5;
public class Base{
  public Base(){             //不带参数的构造方法
    System.out.println("call Base()");
  }
}  

/** Sub.java */
package mypack5;
public class Sub extends Base{
  public Sub(){
    System.out.println("call Sub()");
  }

  public static void main(String args[]){
    Sub b=new Sub();  
  }
}

运行Sub类,会得到以下打印结果:

call Base()
call Sub()

如果把Base类的不带参数的构造方法改为:

public Base(int a){}        //带参数的构造方法

编译Sub类时会出错, 因为Base父类中没有可以被Sub类自动调用的不带参数的构造方法。一种修改方式为:在Sub类的构造方法中,通过super语句显式调用父类的构造方法:

public Sub(){
  super(1);          //调用Base父类的Base(int a)构造方法
  System.out.println("call Sub()");
}

上文参考孙卫琴的经典Java书籍《Java面向对象编程》

探秘Java语言中子类调用父类的构造方法的方式_构造方法_03