简体   繁体   English

最终字段的初始化顺序

[英]Initialization order of final fields

Consider these two classes: 考虑这两个类:

public abstract class Bar {
    protected Bar() {
        System.out.println(getValue());
    }

    protected abstract int getValue();
}

public class Foo extends Bar {
    private final int i = 20;

    public Foo() {
    }

    @Override
    protected int getValue() {
        return i;
    }

    public static void main(String[] args) {
        new Foo();
    }
}

If I execute Foo, the output is 20. 如果我执行Foo,则输出为20。

If I make the field non-final, or if I initialize it in the Foo constructor, the output is 0. 如果我使字段非final,或者我在Foo构造函数中初始化它,则输出为0。

My question is: what is the initialization order in case of final fields and where is this behavior described in the JLS? 我的问题是:在最终字段的情况下,初始化顺序是什么?JLS中描述了这种行为?

I expected to find some exceptional rule about final fields here , but unless I miss something, there isn't. 我希望找到最终的领域一些特殊的规则在这里 ,但除非我错过了什么,没有。

Note that I know I should never call an overridable method from a constructor. 请注意,我知道我永远不应该从构造函数中调用可覆盖的方法。 That's not the point of the question. 这不是问题的关键。

Your final int i member variable is a constant variable: 4.12.4. 你的final int i成员变量是一个常量变量: 4.12.4。 final Variables final变量

A variable of primitive type or type String , that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable . 原始类型或类型String变量是final并使用编译时常量表达式(第15.28节)初始化,称为常量变量

This has consequences for the order in which things are initialized, as described in 12.4.2. 这会对事物初始化的顺序产生影响,如12.4.2所述。 Detailed Initialization Procedure . 详细的初始化程序

Walking you through how this looks in a "byte-code-ish" way. 通过“字节代码”方式向您介绍它的外观。

You should already be aware, that the first actual instruction in a constructor must be a call to super (whether with arguments or without). 您应该已经知道,构造函数中的第一个实际指令必须是对super的调用(无论是带参数还是没有参数)。

That super instruction returns when the parent constructor is finished and the super "object" is fully constructed. 当父构造函数完成并且超级“对象”完全构造时,该超级指令返回。 So when you construct Foo the following happens (in order): 因此,当您构造Foo ,会发生以下情况(按顺序):

// constant fields are initialized by this point
Object.construction // constructor call of Object, done by Bar
Bar.construction // aka: Foo.super()
callinterface getValue() // from Bar constructor
// this call is delegated to Foo, since that's the actual type responsible
// and i is returned to be printed
Foo.construction

if you were to initialize it in the constructor, that would happen "now", after getValue() had already been called. 如果你要在构造函数中初始化它,那么在getValue()被调用之后会发生“现在”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM