4

我有一堂课

public class MyMain{
    public static void main(String... arg){
            Temp t = new Temp(){
                {
                    System.out.println(" instance initialize");
                }
            };

        }
    }

class Temp{
    int i;

    {
        i=9;
        System.out.println("Static"+i);
    }
    Temp(){
        System.out.println("Temp const "+i);
    }
}

当我执行 main 方法时,输出如下:

Static9
Temp const 9
instance initialize

理想情况下,块在构造函数之前执行,但内联初始化块在构造函数之后调用。为什么?

4

7 回答 7

16

正在创建. Temp对于每个类,任何实例初始化程序都在构造函数主体之前执行 - 但超类在子类初始化之前进行初始化。所以执行流程是:

  • 初始化器在Object
  • 构造函数体Object
  • 初始化器在Temp
  • 构造函数体Temp
  • 匿名类中的初始化器
  • 匿名类中的构造函数主体(无)

我强烈建议你重构任何看起来像这样的代码——目标是清晰而不是聪明。

于 2012-05-21T16:51:07.130 回答
6

JLS 12.5阐明了施工过程中发生的事情的顺序(强调我的):

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

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

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

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

总而言之,超类构造函数(第 3 步)在实例初始化程序(第 4 步)之前执行。两者都在“此构造函数的其余部分”(您的示例中没有)之前执行。

于 2012-05-21T16:52:09.117 回答
2

在您正在实例化的匿名类的基类的构造函数之后和匿名类本身的空隐式构造函数之前调用内联初始化块。

于 2012-05-21T16:52:00.740 回答
2

您实际创建的不是Temp类实例,而是某个匿名类的实例,它继承自Temp.

因此,首先Temp调用初始化器(内部的匿名块Temp及其构造器),然后调用匿名类中的初始化器。

于 2012-05-21T16:53:46.967 回答
2

在您的代码中

Temp t = new Temp(){
    {
        System.out.println(" instance initialize");
    }
};

您正在创建扩展 Temp 类的匿名类对象。

创建子类的对象:

initialize block from Superclass
constructor of Superclass
initialize block from Subclass
constructor of Subclass
于 2012-05-21T17:07:41.483 回答
1

第 1 点:需要明确的是,您有两个实例初始化器:一个在 Temp 类中,一个在在 main() 方法中创建的匿名内部类中,该方法是 Temp 的子类。

第 2 点:实例初始化程序实际上并没有在构造函数之前运行。根据 JLS,它们在构造函数期间运行,在委托给超级构造函数之后以及在初始化实例字段和完成构造函数之前。

第 3 点:在您的代码中,每个初始化程序都在适当的时间正确执行。我认为您希望第二个与第一个同时执行,但这是不正确的,因为正如第 1 点所指出的,它们是两个不同类的初始化程序。

第 4 点:您可能还会对静态初始化程序和实例初始化程序感到困惑。它们是两个截然不同的东西。

于 2012-05-21T16:58:17.947 回答
0

该对象必须首先在内存中,然后才能对其进行任何其他操作。该对象在内存中构造,然后您的控制台打印发生。

于 2012-05-21T16:49:26.330 回答