【问题标题】:what happens if super class doesn't have constructor and sub class has constructor that doesnot call to super class constructor by itself [duplicate]如果超类没有构造函数并且子类具有不调用超类构造函数的构造函数会发生什么[重复]
【发布时间】:2021-07-24 21:43:04
【问题描述】:

假设有两个类 A 和 B,B 继承了 A。

现在我们还没有为 A 创建一个构造函数。

但另一方面,我们为 B 创建了一个构造函数,并没有调用 A 类的构造函数。

然后会发生什么以及为什么

编辑:我创建这个问题主要是考虑 java 中的问题

【问题讨论】:

  • 这取决于语言。有些可能隐式调用基本构造函数,有些可能需要您显式调用。您可能想指定您感兴趣的语言。
  • 这能回答你的问题吗? Will the base class constructor be automatically called?。对于 java stackoverflow.com/questions/34488484/…。但是大多数其他oo语言的原理也是一样的
  • 是的,实际上我在考虑java中的问题。这个问题在我脑海中有一段时间,所以我运行了不同的代码来检查它是如何工作的。现在我清楚地了解了工作原理,我尽力解释它,以便像我这样的其他人从中受益。
  • 每个类都有一个构造函数,每个子类构造函数调用一个超级构造函数(即使只是隐式的)。

标签: java inheritance constructor default super


【解决方案1】:

听起来你描述的代码是这样的:

class A {}

class B extends A {
  B() {}
}

语言规范中有两个部分与问题相关。

首先,Section 8.8.7 表示如果构造函数主体不是以 this(...)super(...) 开头,那么它隐含地以 super() 开头,这是对超类的无参数构造函数的调用。

这意味着B 实际上看起来像:

class B extends A {
  B() {
    super();
  }
}

(尝试比较带有和不带有显式 super() 调用的字节码,您会发现它们是相同的)

要编译,A 必须有一个无参数构造函数。

虽然它显然没有构造函数,但语言规范的第二个相关位是Section 8.8.9:当没有显式声明构造函数时,将隐式声明默认构造函数。这与类具有相同的访问修饰符,并且不带参数。

这意味着A 实际上看起来像:

class A {
  A() {
    super(); // call to superclass constructor because of Sec 8.8.7, that is, Object().
  }
}

(再次尝试显式声明此构造函数并比较字节码)

这样的默认构造函数对于类调用超类构造函数是必需的,以便实例在使用前完全初始化。

【讨论】:

    【解决方案2】:

    我解释了它在 java 中的工作原理

    好的,所以我自己创建了这个问题,因为乍一看有点令人困惑。我会尽力解释答案。

    它的作用和原因:

    了解情况: A 类被 B 类继承。 但是由于我们还没有创建 A 类构造函数,所以创建了一个默认构造函数。

    现在请记住,默认构造函数中没有任何参数。

    现在,由于 B 类在创建其对象时有一个构造函数,所以调用了这个构造函数。由于我们没有在子类构造函数中调用超类构造函数,所以默认调用它。

    请记住,如果它默认调用超类构造函数,则在调用该构造函数时不会传递任何参数。您可以假设它放置了一个 super();在B类构造函数的第一行。

    正如乔纳森·罗森所说:

    The Java Language Specification 说“如果构造函数体不是以显式构造函数调用开始并且被声明的构造函数不是原始类 Object 的一部分,那么构造函数体隐式地以超类构造函数调用“super(); “,调用其直接超类的构造函数,不带参数。”。注意句尾 - 没有参数

    最终答案: 现在,作为一个超类构造函数被调用,没有任何参数,并且它已经在超类中创建了一个没有任何参数的默认构造函数,这个默认构造函数被子类构造函数调用。

    默认类构造函数完成它的工作并为所有变量赋予默认值,然后将控制权传递回子类构造函数,它会执行我们在子类构造函数中提到的任何事情。

    通过推断这个答案来解决其他问题:

    • 1.所以如果你在超类中创建了一个构造函数但它没有任何参数,那么你可能会也可能不会在子类构造函数中调用它,结果是一样的。要么你必须写 super();或者默认添加在子类构造函数的第一行。

    • 2.如果你有一个有参数的超类构造函数,那么你必须在子类构造函数中调用它,否则它会默认调用一个没有任何参数的超类构造函数,因为我们在超类中创建了一个参数化的构造函数,它将不会调用默认或非参数化构造函数,并且会导致 constructor not found 错误。

    【讨论】:

    • 我希望它解释了关于这个问题需要理解的一切,即使这个概念很简单,但在看这个问题时,它可能看起来势不可挡。所以我建议保持冷静,一步一步去解决问题,得出最终的结论。
    • 我建议您通过引用Java Language Specification 来加强您的答案,其中说“如果构造函数主体不是以显式构造函数调用开头并且被声明的构造函数不是原始类对象的一部分,然后构造函数体隐式地以超类构造函数调用“super();”开始,这是对其直接超类的构造函数的调用,不带参数。”。注意句尾 - no arguments.
    • @JonathanRosenne 感谢您的回复,我进行了编辑并在答案中包含了您的有用信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    • 1970-01-01
    • 2020-10-31
    • 2013-07-19
    • 1970-01-01
    • 2016-05-08
    相关资源
    最近更新 更多