【问题标题】:Inline initialization blocks in javajava中的内联初始化块
【发布时间】:2012-05-21 16:46:25
【问题描述】:

我有课

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

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

【问题讨论】:

标签: java initialization


【解决方案1】:

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

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

我强烈建议您重构任何看起来像这样的代码 - 力求清晰而不是聪明。

【讨论】:

  • 在 C# 中的行为是否相同?
  • @Gab:不,不完全是。在 C# 中,派生类中的变量初始值设定项在基类中的构造函数之前执行。
【解决方案2】:

JLS 12.5 说明了构建过程中发生的事情的顺序(重点是我的):

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

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

(4) 执行该类的实例初始化器和实例变量初始化器,为实例变量赋值 对应实例变量的初始化器,在 它们在源代码中以文本形式出现的从左到右的顺序 为班级。如果执行这些初始化程序中的任何一个导致 异常,则不再处理任何初始化程序,这 过程突然完成,但出现同样的异常。否则, 继续第 5 步。

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        在您的代码中

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

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

        创建子类的对象:

        initialize block from Superclass
        constructor of Superclass
        initialize block from Subclass
        constructor of Subclass
        

        【讨论】:

          【解决方案6】:

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

          第 2 点:实例初始化程序实际上并未在构造函数之前运行Per the JLS, they're run during a constructor,在委托给超级构造函数之后,在初始化实例字段和完成构造函数之前。

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

          第 4 点:您可能还会对静态 initializers and instance initializers 感到困惑。它们是两种截然不同的东西。

          【讨论】:

            【解决方案7】:

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

            【讨论】:

              猜你喜欢
              • 2011-11-09
              • 1970-01-01
              • 2011-06-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-02-26
              • 1970-01-01
              相关资源
              最近更新 更多