父类的构造方法不能被子类继承。假定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虚拟机首先执行父类的构造方法,再执行子类的构造方法。在多级继承的情况下,将从继承树的最上层的父类开始,依次执行各个类的构造方法。
大力向卫琴请教创建子类对象,先调用父类构造方法的意义
创建子类实例时,先调用父类构造方法,再调用子类构造方法
在例程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面向对象编程》