【问题标题】:Is it true that calling this() inside a constructor implicitly calls super()?在构造函数中调用 this() 是否会隐式调用 super()?
【发布时间】:2015-01-28 11:48:30
【问题描述】:

我试图理解

为什么 this() 和 super() 不能一起使用?

我已经阅读了许多关于 stackoverflow 的相关讨论,并且理解了很多东西。但我仍然有一个困惑。

在构造函数中调用 this() 会隐式调用 super()

考虑一下这段代码..

class Top
{
    int z;
    Top()
    {
        System.out.println("Top default constructor");
    }

}
class A extends Top
{
    int x;
    A(int num)
    {
        x=num;
        System.out.println("A parameterized constructor");
    }
    A()
    {
        this(5);
        System.out.println("A default constructor");
    }
    public static void main(String arg[])
    {
        new A();
    }
}

输出是:

顶级默认构造函数

参数化构造函数

默认构造函数

我没想到输出“顶级默认构造函数”中的第一行,因为没有隐式或显式的 super() 调用。

所以,我可能误解了一些东西。请解释一下。

【问题讨论】:

  • Simpe 规则:构造函数中的第一条语句必须是对另一个构造函数的调用——在同一类 (this(...)) 或父类 (super(...)) 中。如果省略显式构造函数调用,编译器将自动生成对 super() 的隐式调用 - 无参数父构造函数 - 作为第一条语句。
  • 其实有一个隐式的 super() 调用。它没有明确写下来,但它是隐含的(按标准)
  • 警告! “默认构造函数”是当类中没有显式构造函数时,编译器在类中添加的隐式构造函数。如果在类中添加构造函数,则隐含的构造函数就会消失。 Top(){} 和 A(){} 不是默认构造函数,没有参数构造函数,是不同的!默认构造函数具有与类相同的访问修饰符,无参数,并且在其第一行具有 super()。你看不到它,它是在编译时添加的。

标签: java class constructor


【解决方案1】:

在构造函数中调用 this() 是否会隐式调用 super()?

在构造函数中调用this() 将调用该类的零参数构造函数。如果该类的零参数构造函数没有显式调用super(...),那么是的,将会有一个隐式调用零参数super() 构造函数。如果你的类中的零参数构造函数显式调用了其他一些super 签名,那么当然会这样做。

这对于一般的构造函数来说是正确的。在您的 A 类中,由于您的 A(int) 构造函数没有对 this() super() 的任何调用,因此隐式 super() 已完成。

我没想到输出“顶级默认构造函数”中的第一行,因为没有 super() 调用,隐式或显式。

是的,有——隐含的。 :-)

基本规则是这样的:一些基类构造函数必须在派生类中的代码运行之前运行。这就是为什么对this(...)super(...) 的调用必须是构造函数中的first 事物。如果构造函数没有对super(...) 的显式调用,则始终会隐式调用super()(没有参数)。

【讨论】:

    【解决方案2】:

    在构造函数中调用this() 会调用同一类的另一个构造函数。另一个构造函数将调用super() 构造函数(隐式或显式),这就是为什么您不能在同一个构造函数中同时调用this()super(),因为这会导致调用两个super() 构造函数。

    请注意,每当我写 this()super() 时,我并不一定是指调用无参数构造函数(除了对 super() 的隐式调用,它总是调用 super 的无参数构造函数类,正如 Joeblade 所评论的那样)。两个调用都可以有参数。

    在您的代码示例中,A() 构造函数调用 A(int) 构造函数(这就是 this(5) 所做的),它隐式调用 Top()(无参数)构造函数。

    【讨论】:

    • 很好的答案,但 super() 实际上是不带参数的构造函数,当它被隐式调用时。任何其他用途都必须显式调用。
    【解决方案3】:

    this(5) 调用 A(int num) 隐式调用 super()

    【讨论】:

      【解决方案4】:

      Creation of New Class Instances 的 Java 语言规范部分对此进行了解释,重点是用粗体标记的超类构造函数:

      就在对新创建对象的引用作为结果返回之前,使用以下过程处理指示的构造函数以初始化新对象:

      1. 将构造函数的参数分配给此构造函数调用新创建的参数变量。

      2. 如果此构造函数以同一类中另一个构造函数的显式构造函数调用(第 8.8.7.1 节)开始(使用 this),则评估参数并使用这五个相同的步骤递归地处理该构造函数调用。如果该构造函数调用突然完成,则此过程出于相同原因而突然完成;否则,继续第 5 步。

      3. 此构造函数不是以显式构造函数调用同一类中的另一个构造函数开始的(使用 this)。 如果此构造函数用于 Object 以外的类,则此构造函数将从显式或隐式调用超类构造函数开始(使用 super)。使用这五个相同的步骤以递归方式评估超类构造函数调用的参数和过程。如果该构造函数调用突然完成,则此过程出于相同的原因突然完成。否则,继续第 4 步。

      4. 执行该类的实例初始化程序和实例变量初始化程序,将实例变量初始化程序的值分配给相应的实例变量,按照它们在源代码中以文本形式出现的从左到右的顺序。如果执行这些初始化程序中的任何一个导致异常,则不会处理更多初始化程序,并且此过程会突然完成相同的异常。否则,继续第 5 步。

      5. 执行此构造函数的其余部分。如果该执行突然完成,则此过程出于同样的原因突然完成。否则,此过程正常完成。

      因此,在您的情况下,当使用 this(5) 调用构造函数 A(int num) 时,第 3 步表示它隐式调用超类构造函数,递归地应用相同的过程。

      请注意,您可以通过调试构造函数调用的顺序来遵循该过程。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-17
        • 2015-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多