子类构造函数 - 为什么子类构造函数必须存在默认构造函数?

4

给定一个随机的类:

public class A<T> {
    public T t;

    public A () {}  // <-- why is this constructor necessary for B?
    public A (T t) {
        this.setT(t);
    }
    public T getT () {
        return this.t;
    }
    protected void setT (T t) {
        this.t = t;
        return;
    }
}

还有一个扩展类:

public class B extends A<Integer> {
    public B (Integer i) {
        this.setT(i);
    }
}

为什么B要求A有空构造函数?我原以为它会想要使用相似的构造函数而不是默认构造函数。我尝试编译没有默认构造函数的代码,但是我却得到了以下错误消息...
java.lang.NoSuchMethodError: A: method <init>()V not found at B.<init>

有人能解释一下这是为什么吗?
3个回答

11
重要的是要明白任何构造函数的第一行都是调用 super 构造函数。如果您没有自己调用超类构造函数,编译器会在幕后插入 super() 以使您的代码更短。
此外,如果您没有任何构造函数,空的默认构造函数 - 这里是 A()B() - 将被自动插入。
在 B 构造函数中没有 super(...) 的情况下,编译器会自动插入 super() 调用,但是您具有带参数的 A 构造函数,因此不会插入默认的 A()-构造函数,并且您必须手动提供 A()-构造函数,或者改为调用 A(i)-构造函数。在这种情况下,我建议只需...
public class B extends A<Integer> {
    public B (Integer i) {
        super(i);
    }
}

当一个对象被实例化时,是否可以说它继承的所有对象也被实例化了(就像积木一样)? - Zak
我更愿意说,当你实例化一个对象时,构造函数负责初始化该对象。如果你对其进行子类化,子类的构造函数负责初始化新增部分,而超类的构造函数负责其余部分的初始化。这个过程递归地一直延伸到Object类本身。 - Thorbjørn Ravn Andersen

6

你可以在A中使用自己的构造函数,但是你必须从B的构造函数中显式调用它,例如:

public B(Integer i) {
  super(i);
  ...
}

如果你不这样做,编译器将尝试通过调用其默认构造函数来实例化A


2
如果您在构造函数的第一行不使用super(i)调用超类构造函数,它将隐式地调用默认的超类构造函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接