为什么实例初始化程序块在声明之前先引用一个字段? [英] Why can my instance initializer block reference a field before it is declared?

查看:56
本文介绍了为什么实例初始化程序块在声明之前先引用一个字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的理解是,在声明变量之前不能引用它,并且在类的主体内但在任何方法之外的所有代码(包括实例初始化器)将在构造函数之前按顺序执行.对象被创建( static 变量和初始化程序块除外,它们在程序开始时按顺序运行,以初始化整个类).那么,为什么下面的代码会编译(并运行!):

My understanding is that you cannot reference a variable before it has been declared, and that all code (including instance initializers) that is within the body of a class, but outside of any method, is executed in order before constructor when the object is created (the exception being static variables and initializer blocks, which are run in order at the beginning of the program, to initialize the entire class). Why, then, does the following code compile (and run!):

public class WhyIsThisOk {
    { a = 5; } // why is this ok???
    int a = 10;

    public WhyIsThisOk() {
    }

    public static void main(String[] args) {
        WhyIsThisOk why = new WhyIsThisOk();
        System.out.println(why.a); // 10
    }
}

推荐答案

来自

Java编译器将初始化程序块复制到每个构造函数中.因此,该方法可用于在两个程序之间共享一个代码块多个构造函数.

The Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors.

上面的陈述有些误导,因为如果按照上面文档的解释,我们可以像这样重写原始代码:

The above statement is slightly misleading, because if we follow the explanation of the above doc we can rewrite the original code like this:

public class WrongVersionOfWhyIsThisOk {

    int a = 10;

    public WhyIsThisOk (){
        a = 5;
    }

    public static void main(String[] args){
        WrongVersionOfWhyIsThisOk why = new WrongVersionOfWhyIsThisOk ();
        System.out.println(why.a);
    }
}

但是运行 WrongVersionOfWhyIsThisOk 会产生5而不是原始代码产生的10.

But running WrongVersionOfWhyIsThisOk will produce 5 instead of 10 that original code produces.

但是实际上,初始化程序块和变量赋值都被复制到构造函数中:

But in reality it is both the initializer block and variable assignment are copied into constructor:

public class RightVersionOfWhyIsThisOk {

    int a;

    public RightVersionOfWhyIsThisOk (){
        a = 5;
        a = 10;
    }

    public static void main(String[] args){
        RightVersionOfWhyIsThisOk why = new RightVersionOfWhyIsThisOk ();
        System.out.println(why.a);
    }
}

更新:

这是 doc 详细描述初始化顺序和构造函数调用:

Here is the doc describing in detail the initialization order and constructor invocation:

4)执行实例初始化器和实例变量此类的初始化程序,分配实例变量的值初始化为对应的实例变量,在从左到右的顺序,它们在源代码中以文本形式显示上课.如果执行这些初始化程序中的任何一个都会导致异常,则不会再处理其他初始化程序,并且这程序突然完成,但有相同的例外.除此以外,继续执行步骤5.

4) Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5.

5)执行此构造函数的其余部分.如果执行突然完成,然后此步骤突然完成同样的原因.否则,此过程将正常完成.

5) Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.

这篇关于为什么实例初始化程序块在声明之前先引用一个字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆