这篇文章总结了常见关于Java构造器的问题。

1.为什么创建子类对象的时候同样需要调用父类的构造函数?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Super {
String s;
public Super(){
System.out.println("Super");
}
}
public class Sub extends Super {
public Sub(){
System.out.println("Sub");
}
public static void main(String[] args){
Sub s = new Sub();
}
}

输出结果是:

Super
Sub

当从另一个类继承时,在构造函数被调用时候第一调用super()。如果不是编译器将会插入这个规则。这就是为什么超类构造函数总是在子类对象创建的时候被调用。

这不会创建2个对象,只会创建了一个Sub对象。父类构造函数需要调用的原因是害怕有时候父类需要实例化一下私有数据。

经过编译,会加入父类构造函数,子类的构造函数如下所示:

1
2
3
4
public Sub(){
super();
System.out.println("Sub");
}

2.一个常见的错误:Implicit super constructor is undefined for default constructor

这是很多java开发者会遇见的错误:

“Implicit super constructor is undefined for default constructor. Must define an explicit constructor”

编译错误图

发生这种编译错误,是因为默认的父类构造函数是不确定的。在Java中,如果一个类没有定义构造函数,编译器会插入一个默认的无参数构造函数。如果构造函数是在父类中定义了的,在这种情况下,已经有Super(String s)构造函数,编译器将不插入默认的无参数构造函数。所以引起上述情况。

在子类的构造函数中,要么是使用参数的构造函数或不写(不写将调用父类的无参的构造函数)。由于编译器试图插入super()到子类的2个构造,但父类的默认构造函数是没有定义的使用,编译器报错。

要解决此问题,第一种方式是在父类增加一个Super() 的构造函数,如下:

1
2
3
public Super(){
System.out.println("Super");
}

第二种是移除自定义的构造函数。第三种是在子类中添加super(value)调用。

3.显示调用超类中的构造函数

下面的代码OK:

显示调用超类中的构造函数

因为Sub构造方法中显示的声明了调用超类中的有参构造函数,使用就是可以的。

4.习惯或者规范

最好的方式是:在子类构造需要调用父类构造初始化,那么最好显示调用。

5. 有趣的问题

为什么Java不提供默认的构造函数,如果类已经具有有参构造函数时?

可以看看stackoverflow上的一些回答

参考文档