在 Java 中定义⼀个不做事且没有参数的构造⽅法的作⽤,比如下面的代码:
class Father {
private String str;
// 这个空构造方法有什么作用呢?
Father(){
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
void print(){
System.out.println(str);
}
}
这个问题出现在子类与父类之中,如下面的代码:
class Father {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
void print(){
System.out.println(str);
}
}
class Son extends Father {
private String sonStr;
Son(String str){
this.sonStr=str;
}
@Override
void print() {
System.out.println(sonStr);
}
}
上面的代码不会报任何编译上的错误。
Java 程序在执⾏⼦类的构造⽅法之前,如果没有⽤ super() 来调⽤⽗类特定的构造⽅法,则会调
⽤⽗类中“没有参数的构造⽅法”,父类没有自己的构造方法,所以系统会默认给父类配置一个没有参数的构造方法,所以代码能够正确编译。
但注意,一旦父类有了属于自己的非空参数构造方法后,系统将不会再赠送父类没有参数的构造方法。
如下面的代码:
class Father {
private String str;
Father(String str){
this.str=str;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
void print(){
System.out.println(str);
}
}
class Son extends Father {
private String sonStr;
Son(String str){
this.sonStr=str;
}
@Override
void print() {
System.out.println(sonStr);
}
}
会报编译上的错误:
因此,如果⽗类中只定义了有参数的构造⽅法,⽽在⼦类的构造⽅法中⼜没有⽤ super() 来调⽤⽗类中特定的构造⽅法,则编译时将发⽣错误,因为 Java 程序在⽗类中找不到没有参数的构造⽅法可供执⾏。
解决方法就是子类实现父类的有参构造方法,或者在父类中自己添加一个没有参数的构造方法。
在父类中添加一个无参构造方法
看下面的代码也没有报编译上的错误:
class Father {
private String str;
Father(){};
Father(String str){
this.str=str;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
void print(){
System.out.println(str);
}
}
class Son extends Father {
private String sonStr;
Son(String str){
this.sonStr=str;
}
@Override
void print() {
System.out.println(sonStr);
}
}
因为父类有了一个无参的构造方法,子类在调用自己的构造方法时会默认调用父类的无参构造方法。
如果要问为什么子类必须调用父类的构造方法,那么回答就是没有父亲哪来的儿子,要使用的父类的属性和方法,也必须实例化父类对象,而空参构造方法可以实例化父类对象。
执行下面的代码:
class Father {
private String str;
Father() {
}
Father(String str) {
this.str = str;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
void print() {
System.out.println(str);
}
}
class Son extends Father {
private String sonStr;
Son(String str) {
this.sonStr = str;
}
@Override
void print() {
System.out.println(sonStr);
}
}
public class Demo {
public static void main(String[] args) {
Son son = new Son("abc");
son.print();
}
}
然后找到Son.class文件,右键单击打开Terminal面板
执行javap -c Son.class命令,反编译生成的class文件,生成的内容如下:
Compiled from "Demo.java"
class Son extends Father {
Son(java.lang.String);
Code:
0: aload_0
1: invokespecial #1 // Method Father."<init>":()V
4: aload_0
5: aload_1
6: putfield #2 // Field sonStr:Ljava/lang/String;
9: return
void print();
Code:
0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: getfield #2 // Field sonStr:Ljava/lang/String;
7: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: return
}
可以看到子类调用了父类的无参构造方法,实例化父类对象。
总结:
- 子类实例化对象时,必定会调用自己的构造方法,在自己的构造方法中又必定会调用父类的构造方法(默认调用父类的无参构造方法)。
- 如果父类没有任何构造方法,那么不会报编译上的错误,因为系统会赠送父类一个无参构造方法,但如果父类有带参数的构造方法,那么系统不会赠送父类无参构造方法了,那么子类中如果没有使用super()调用父类的有参构造方法,会报编译上的错误。
- 解决方法就是在父类上添加一个无参构造方法,那么子类在实例化对象时,直接默认调用父类的无参构造方法,不会产生编译上的问题。
- 因此一个不做事且没有参数的构造方法的作用就是让子类继承父类的时候能够默认调用无参构造方法顺利实例化父类对象,而不至于产生编译上的错误。
- 在调用子类构造方法之前会先调用父类的无参构造方法,目的是帮助子类完成初始化工作。