简体   繁体   English

最终字段初始化顺序

[英]Final fields initialization order

Here is some code that calls static method Af() on class that is not initialized yet. 下面是一些在尚未初始化的类上调用静态方法Af()的代码。 Can someone explain behavior of this code in terms of JLS? 有人可以用JLS来解释这段代码的行为吗?

class A {
    final static Object b = new B();
    final static int S1 = 1;
    final static Integer S2 = 2;

    static void f() {
        System.out.println(S1);
        System.out.println(S2);
    }
}

class B {
    static {
        A.f();
    }
}

public class App
{
    public static void main( String[] args )
    {
        A.f();
    }
}

Output: 输出:

1
null
1
2

Af() in App.main() triggers initialization of class A . App.main() Af()触发AA初始化。

All constant variables are initialized. 初始化所有常量变量。 The only constant variable is S1 , which now is 1 . 唯一的常量变量是S1 ,现在为1

Then, the other static fields are initialized in textual order. 然后,以文本顺序初始化其他静态字段。 b is the first field, which triggers initialization of class B , which in turn calls Af() . b是第一个字段,它触发B类的初始化,而B类又调用Af() S2 is simply null because it is not initialized yet. S2只是null因为它尚未初始化。 Initialization of b is now complete. b初始化现已完成。 Last but not least, S2 is initialized to the Integer object 2 . 最后但并非最不重要的是, S2被初始化为Integer对象2

S2 is not a constant variable because it is not of the primitive type int but of the reference type Integer . S2不是常量变量,因为它不是基本类型int而是引用类型Integer S2 = 2; is an auto-boxing shorthand for S2 = Integer.valueOf(2); S2 = Integer.valueOf(2);的自动拳击简写S2 = Integer.valueOf(2); .

If a declarator in a field declaration has a variable initializer, then the declarator has the semantics of an assignment (§15.26) to the declared variable. 如果字段声明中的声明符具有变量初始值设定项,则声明符具有声明变量的赋值(第15.26节)的语义。

[…] [...]

Note that static fields that are constant variables (§4.12.4) are initialized before other static fields (§12.4.2). 需要注意的是static字段是不变的变量(§4.12.4)先于其他初始化static字段(§12.4.2)。 This also applies in interfaces (§9.3.1). 这也适用于接口(第9.3.1节)。 Such fields will never be observed to have their default initial values (§4.12.5), even by devious programs. 即使是狡猾的程序,也永远不会观察到这些字段具有默认的初始值(§4.12.5)。

8.3.2. 8.3.2。 Field Initialization 场初始化

A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28). 常量变量是基本类型或类型Stringfinal变量,使用常量表达式(第15.28节)初始化。 Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1, §13.4.9), and definite assignment (§16 (Definite Assignment)). 变量是否是常量变量可能对类初始化(第12.4.1节),二进制兼容性(第13.1节,第13.4.9节)和明确赋值(第16节(定义赋值))有影响。

4.12.4. 4.12.4。 final Variables final变量

A constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following: 常量表达式是表示基本类型值的表达式或不突然完成的String ,仅使用以下内容组成:

  • Literals of primitive type and literals of type String 原始类型的文字和String类型的文字

[…] [...]

15.28. 15.28。 Constant Expressions 常数表达式

For each class or interface C, there is a unique initialization lock LC . 对于每个类或接口C,存在唯一的初始化锁定LC The mapping from C to LC is left to the discretion of the Java Virtual Machine implementation. 从C到LC的映射由Java虚拟机实现决定。 The procedure for initializing C is then as follows: 初始化C的过程如下:

[…] [...]

  1. Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC . 否则,记录当前线程正在进行C的Class对象初始化并释放LC的事实。

    Then, initialize the static fields of C which are constant variables (§4.12.4, §8.3.2, §9.3.1). 然后,初始化C的static字段,它们是常量变量(§4.12.4,§8.3.2,§9.3.1)。

[…] [...]

  1. Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block. 接下来,按文本顺序执行类的类变量初始值设定项和类的静态初始值设定项,或接口的字段初始值设定项,就好像它们是单个块一样。

12.4.2. 12.4.2。 Detailed Initialization Procedure 详细的初始化程序

Every variable in a program must have a value before its value is used: 程序中的每个变量在使用其值之前必须具有值:

  • Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10.2): 每个类变量,实例变量或数组组件在创建时都会使用默认值进行初始化(§15.9,§15.10.2):

    […] [...]

    • For all reference types (§4.3), the default value is null . 对于所有引用类型(第4.3节),默认值为null

4.12.5. 4.12.5。 Initial Values of Variables 变量的初始值

It seems that this issue doesn't belong to JLS , but we have deal with JVMS . 看来这个问题不属于JLS ,但我们处理JVMS

On Linking stage before resolution process there is Preparation substage, which involves: resolution过程之前的Linking阶段有准备子阶段,其中包括:

creating the static fields for a class or interface and initializing such fields to their default values 为类或接口创建静态字段并将这些字段初始化为其默认值

and more: 和更多:

explicit initializers for static fields are executed as part of initialization (§5.5), not preparation 静态字段的显式初始化程序作为初始化(第5.5节)的一部分执行,而不是准备

while initialization includes: 初始化包括:

The execution of any one of the Java Virtual Machine instructions new 执行任何一个Java虚拟机指令都是新的

Initializing of primitive types includes writing their initial value. 初始化基元类型包括写入它们的初始值。 For reference type fields their default value is null because before Resolution substage jvm doesn't "know" which class is associated to apropriate symbolic reference name of a class. 对于引用类型字段,它们的默认值为null因为在解析子阶段之前,jvm“不知道”哪个类与类的适当符号引用名相关联。

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

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