定义子类时,它不会从超类继承构造函数。对于默认超类构造函数以外的任何内容,您都需要在每个子类构造函数中显式调用超类构造函数。(这意味着,除其他外,如果基类没有默认构造函数,则任何子类也不能每个子类构造函数都必须显式调用超类构造函数——并且任何子类都不能仅具有编译器生成的默认构造函数。有一个例外;请参阅下面的[*]。)
继承构造函数可能会导致各种问题。想象一下这样的事情:
class Base {
private int mId;
public Base(int id) {
mId = id;
}
. . .
}
现在我们要派生一个具有第二个属性的类——一个标签——我们要确保它是 never null
。所以我们写如下:
class Derived extends Base {
private Object mTag;
public Derived(Object tag, int id) {
super(id);
if (tag == null) {
throw new IllegalArgumentException("tag cannot be null");
}
mTag = tag;
}
. . .
}
现在想象构造一个Derived
这样的实例:
Derived derived = new Derived(3);
如果构造函数被继承,这可能是合法的。这意味着什么?一方面,mTag
将设置为其默认值null
. 没有办法Derived
强制执行所有实例都Derived
必须具有非空标记的规则。
以需要更多输入为代价,Java 精确地排除了继承构造函数,以允许每个类完全控制其实例的创建方式。
[*]在一种情况下,编译器会自动生成一个非默认构造函数。考虑Base
上面的类和这段代码:
Base foo = new Base(3) {
. . . // some extended functionality
};
现在foo
正在初始化为Base
. 为了方便参考,我们称这个子类Base$Anon
。编译器将生成等效于:
class Base$Anon extends Base {
Base$Anon(int id) {
super(id);
}
. . . // some extended functionality
}
Base foo = new Base$Anon(3);
如果您不指定自己的任何构造函数,这是编译器生成非默认构造函数的唯一情况。事实上,语言语法甚至不允许您为匿名类声明构造函数。您必须依靠编译器为您生成一个。