1
class Alpha
{
       String name = "Alpha";
       Alpha()
       {
           print();
       }
       void print()
       {
           System.out.println("Alpha Constructor");
       }
}
class Beta extends Alpha
{
       int i =   5;
       String name = "Beta";
       public static void main(String[] args)
       {
          Alpha a = new Beta();
          a.print();//Line1 executes Beta constructor
          System.out.println(a.name);//Line 2 displays Alpha instance variable
       }
       void print()
       {
           System.out.println(i);
       }
}

该程序编译成功并显示以下输出。

0
5
Alpha

问题

a) 我不明白为什么 Alpha 的构造函数没有首先执行。

我相信“super()”将首先被每个子构造函数隐式调用......对吗?

b) 如果 Beta 的构造函数已经执行,那么为什么要打印“5”?(输出中的第二行)

我有点理解的第三行(即,将显示 Alpha 自己的变量,因为尚未对“a”实例变量进行强制转换)

4

4 回答 4

5

你在这里犯了两个“重罪”:

  1. 从构造函数调用可覆盖的方法;
  2. 在子类中声明一个与超类同名的实例变量。

这两个习语都会导致令人惊讶的行为。具体来说, 1. 导致Beta#printAlpha的构造函数被调用,这会导致打印0,因为您正在print调用Beta. 这正是因为超构造函数在子类构造函数之前运行。

总之,从构造函数调用重写的方法会导致执行顺序发生不必要的反转:控制从超类构造函数转移到子类方法。

至于您关于为什么5打印的问题:a.print()与 不同a.name的是,它是一种受动态调度的方法调用。因此,无论a' 声明的类型(即Alpha)如何,Beta#print都会调用该方法(在Alpha' 的构造函数中也会发生同样的情况,但在i变量初始化之前)。

于 2013-08-25T10:57:24.487 回答
4
class Alpha
{
       String name = "Alpha";
       Alpha()
       {
           print();

这里实际上调用了Beta.print(),因为它@OverrideAlpha.print(). 由于首先调用基类构造函数,因此该Beta部分尚未在此处初始化,因此它打印 0 因为...

       }
       void print()
       {
           System.out.println("Alpha Constructor");
       }
}
class Beta extends Alpha
{
       int i =   5;

这行代码还没有被执行。类体内的初始化在超类构造函数 ( super()) 之后但在同一类的构造函数体之前执行。

       String name = "Beta";
       public static void main(String[] args)
       {
          Alpha a = new Beta();
          a.print();//Line1 executes Beta constructor

在这里,它将打印 5,因为 Beta ( a) 的初始化已完成。

          System.out.println(a.name);//Line 2 displays Alpha instance variable
       }

这就是说的方法实际上被称为:

       void print()
       {
           System.out.println(i);
       }
}

初始化/调用顺序:

  • Object.Object()
  • Alpha.<instance vars>
  • Alpha.<constructor body>
    • Beta.print()覆盖Alpha.print()(打印Beta.i,仍为 0(默认))
  • Beta.<instance vars>(这里Beta.i会初始化为5)
  • Beta.<constructor body>
  • Beta.print()覆盖Alpha.print()(打印Beta.i,最后是 5,因为初始化完成)
于 2013-08-25T11:08:04.520 回答
1

我不明白为什么 Alpha 的构造函数没有首先执行。

它确实首先执行。我不知道是什么让你认为它没有。也许是输出0。那是因为您在构造函数中调用了重写的方法,它将调用类中的print()方法Beta。现在,由于此时变量i尚未初始化,它将打印 0。有关详细信息,请参阅此答案。我还写了一篇关于这个主题的博客文章。

我相信每个子构造函数都会首先隐式调用“super()”......对吗?

不总是。当您使用 , 链接同一类的构造函数时this()super()不会添加。否则超类构造函数将被链接。

如果 Beta 的构造函数已经执行,那么为什么要打印“5”?

为什么不呢?Beta 构造函数将初始化i5. 您在声明时所做的初始化被编译器移动到您的类的每个构造函数,在super()orthis()语句之后,无论那里有什么。

于 2013-08-25T11:02:52.643 回答
0
  • Alpha 的构造函数首先被执行。如果你System.out.println("Alpha Ctr");输入Alpha()方法,你会注意到Alpha Ctr被打印出来。
  • 事实是您已经覆盖print()了子类中的方法Beta。因此Beta#print()被执行而不是Alpha#print().

如果你稍微改变Beta#print()一下,这种行为会更清楚:

void print() {
    System.out.println(name + ": " + i);
}

现在将打印:

null: 0
Beta: 5
Alpha

在这里打印,因为在构造父类时null: 0变量未初始化。name & iAlpha

于 2013-08-25T11:01:20.747 回答