【问题标题】:Explanation of output输出说明
【发布时间】:2012-12-19 16:56:11
【问题描述】:

我的程序

class Building {
Building() {
    System.out.print("b ");
}

Building(String name) {
    this();
    System.out.print("bn " + name);
}
};

public class House extends Building {
House() {
    System.out.print("h "); // this is line# 1
}

House(String name) {
    this(); // This is line#2
    System.out.print("hn " + name);
}

public static void main(String[] args) {
    new House("x ");
}
}

我们知道编译器将调用super() 作为子类构造函数的第一行。因此输出不应该是:

b(从编译器调用 super(),在第 2 行之前)

b(再次来自编译器对 super() 的调用,在第 1 行之前)

h hn x

但是输出是

b h hn x

这是为什么呢?

【问题讨论】:

  • House(x) -> this() (House()) -> Building ()
  • 如果super() 构造函数被多次调用也没有多大意义——这也可能违反了Java 的构造函数契约。

标签: java output


【解决方案1】:

当构造函数以调用另一个构造函数(thissuper)开始时,编译器不会插入对超类默认构造函数的调用。因此,调用树是:

main
 \-> House(String)                (explicit call)
      |-> House()                 (explicit call)
      |    |-> Building()         (implicit call)
      |    |    |-> Object()      (implicit call)
      |    |    \-> print "b "
      |    \-> print "h "
      \-> print "hn x"

【讨论】:

  • 谢谢。我可以在任何地方阅读更多有关此的信息吗?说标准还是什么?想知道这背后的原因。
  • @Anon - 这一切都在Section 8.8 of the Java Language Specification 中详细说明。为大量密集材料做好准备。 Java tutorial on inheritance 中提供了更温和的介绍(缺少一些细节)。
  • 谢谢。最后一个问题(只是因为一些评论员对我的理解产生了怀疑)隐式调用 super 将在 line#1 或 line#2 之前?
  • @Anon - 对super() 的隐式调用在第 1 行之前。如果构造函数以调用另一个构造函数(任何类型,thissuper)开始,编译器永远不会插入超类构造函数调用。此外,如果构造函数 x 将调用构造函数 y,则对 y 的调用必须是 x 主体中的第一条语句。
【解决方案2】:

根据JLS 8.8.7

如果构造函数主体不以显式构造函数开头 调用和被声明的构造函数不是 原始类 Object,然后构造函数体隐式开始 使用超类构造函数调用“super();”

【讨论】:

  • 谢谢,但实际上我的问题是,为什么 super() 只调用一次
  • @Anon:因为你在 line2 有显式的构造函数调用 this(),如果没有显式的构造函数调用,那么只会发生隐式调用 super()。请再读一遍JLS。
【解决方案3】:

您的House(string name) 构造函数调用House(),而后者又调用Building()Building(string name) 永远不会被调用。

如果您想显式调用Building(string name),可以在House(string name) 构造函数中添加:super(name); 而不是this();

【讨论】:

  • 是的,我知道 Buidling(字符串名称)永远不会被调用,我什至从未提到它会这样。我的问题有所不同。
  • 抱歉,我错过了您放置 // this is line #1 的位置,只是将您的代码用作参考。
【解决方案4】:

这是您的代码的可视化控制流程:

new House("x ")---> House(args)---> House() --->Building()--->Object()
                               ^^this()    ^implicit      ^implicit super() call 
                                             super()
                                             call

--->代表调用

输出: b(from building no-args), h(from no-args House), hn x (from args House) b h hn x

据我所知,对 super 的隐式调用应该在 this() 之前, 正确的?第 2 行,在我的代码中

编辑:

构造函数的第一行是使用 super() 调用超类构造函数或使用 this() 调用重载构造函数。如果使用 this() 调用重载构造函数,则不会调用 super()。

【讨论】:

  • 据我所知,对 super 的隐式调用应该在 this() 之前,对吧?第 2 行,在我的代码中
  • @Anon 不,如果你显式调用重载的 cons,那么该构造函数中不会有 super() 调用,请检查我的编辑。
  • 谢谢。学到了一些新东西。 +1。
【解决方案5】:
House(x) -> House() + "hn" + "x"
            Building() + "h" + "hn" +"x"
            "b" + "h" + "hn" + "x"

对超类的调用只会被调用一次。

如果你想调用Building(string name),你必须显式调用它。

我认为您使用super() 代替this() 会更容易

【讨论】:

  • 我想我现在明白了。我还有一个问题 - 为什么只调用一次 super ?
猜你喜欢
  • 2011-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-24
  • 2017-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多