哪个构造函数被调用

16 浏览
0 Comments

哪个构造函数被调用

假设以下代码。我不明白为什么输出是\nB的构造函数被调用\nA的构造函数被调用。\n我以为输出只是\"A的构造函数被调用\",因为A的构造函数没有调用B的构造函数?\n

public class Test {
    public static void main(String[] args) {
        A a = new A(3);
    }
}
class A extends B {
    public A(int t) {
        System.out.println("A's constructor is invoked");
    }
}
class B {
    public B() {
        System.out.println("B's constructor is invoked");
    }
}

0
0 Comments

如果在子类的构造函数中没有调用任何超类构造函数,那么编译器会自动在子类构造函数的第一条语句中添加一个默认的(无参数)构造函数调用:

class A extends B {
    public A(int t) {
        super(); // 由编译器添加
        System.out.println("A's constructor is invoked");
    }
}

如果超类没有无参构造函数(无论是显式定义的还是隐式的),则会出现编译错误,这意味着您必须在子类构造函数的第一条语句中显式调用一个现有的超类构造函数。

Implicit super constructor B() is undefined. Must explicitly invoke another constructor

如果一个类没有显式定义构造函数,编译器会为其添加一个隐式的无参构造函数。

0
0 Comments

问题的原因是,编译器会自动在每个类的构造函数中添加super(),以调用父类的构造函数。这是因为编译器会自动提供默认构造函数,但它也会将super()添加为第一条语句,以调用基类的构造函数。

解决方法是,如果想要避免编译器自动添加super(),可以在类中定义自己的构造函数。只有在没有其他构造函数存在的情况下,编译器才会添加默认构造函数。所以,在代码中,类B已经包含了一个构造函数,类A包含了一个带参数的构造函数,因此编译器不会提供任何默认构造函数。

如果对Java语言或Java行为有疑问,可以参考Java Language Specification (JLS)和Java Virtual Machine Specification(JVMS)。可以在docs.oracle.com/javase/specs找到它们。默认构造函数在JLS的第8.8.9章中有描述。

总结起来,编译器会自动添加super()调用父类构造函数的语句,但只有在没有其他构造函数存在时才会提供默认构造函数。要避免编译器自动添加super(),可以在类中定义自己的构造函数。

0
0 Comments

当调用派生类的默认构造函数时,基类的默认构造函数会自动调用,对于参数化构造函数也是同样的规则。这就是为什么你会得到这样的输出:

B的构造函数被调用。

A的构造函数被调用。

解决方法:在派生类的构造函数中调用基类的构造函数,可以使用派生类的构造函数成员初始化列表来实现。例如,可以使用以下代码解决这个问题:

class A {
public:
    A() {
        cout << "A's constructor is invoked." << endl;
    }
};
class B : public A {
public:
    B() : A() {
        cout << "B's constructor is invoked." << endl;
    }
};

在这个例子中,派生类B的构造函数中调用了基类A的构造函数。这样,当创建B的对象时,会先调用A的构造函数,再调用B的构造函数。输出结果将是:

B's constructor is invoked.

A's constructor is invoked.

0