类中的静态字段初始化序列

Xep*_*nia 5 java static

当一个类有自己的静态实例时,我无法理解初始化顺序.此外,为什么这种行为似乎有所不同String.

请参阅以下示例:

public class StaticCheck {
    private static StaticCheck INSTANCE = new StaticCheck();    

    private static final List<String> list =
        new ArrayList<String>(Arrays.asList("hello"));
    private static final Map<String, String> map =
        new HashMap<String, String>();  
    private static final  String name = "hello";

    public static StaticCheck getInstance() {
        return INSTANCE;
    }

    private StaticCheck() {
        load();     
    }

    private void load() {
        if(list != null) {
            System.out.println("list is nonnull");
        } else {
            System.out.println("List is null");
        }
        if(name != null) {
            System.out.println("name is nonnull");
        } else {
            System.out.println("name is null");
        }
        if(map != null) {
            System.out.println("Map is nonnull");
        } else {
            System.out.println("Map is null");
        }
    }

    public static void main(String[] args) {
        StaticCheck check = StaticCheck.getInstance();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

List is null
name is nonnull
Map is null
Run Code Online (Sandbox Code Playgroud)

我绝对不清楚为什么该字段name不为空.静态字段在以下情况下初始化,如类初始化中所述:http: //javarevisited.blogspot.in/2012/07/when-class-loading-initialization-java-example.html

看看上面的例子,我的想法是:

  1. 如上所述,在Java中的实例初始化之前初始化静态字段.在这里,当我调用静态方法时getInstance(),它将导致类初始化,这意味着静态字段的初始化.在这种情况下,字段map和和list不应为null.

  2. 在上面的示例中,由于该字段INSTANCE是静态的,因此load()在未初始化其他字段时会发生其对象初始化并且其构造函数会调用.因为这个字段listmap为空.那么为什么name要初始化?我有点困惑.

Roh*_*ain 7

String类型name变量是一个编译时间常数,其通过在编译时,编译器内联.所以,条件:

if (name != null)
Run Code Online (Sandbox Code Playgroud)

编译后将成为:

if ("hello" != null)
Run Code Online (Sandbox Code Playgroud)

这当然是真的.

至于为什么maplistnull,那是因为,当初始化类时,初始化INSTANCE字段,调用构造函数,构造函数又调用该load()方法.请注意,static到目前为止,尚未运行其他初始值设定项.所以,maplist仍在null.所以,用load()方法打印它们null.


rge*_*man 5

常量static变量在初始化任何非static变量之前初始化。JLS第 12.4.2 节规定了类的初始化过程:

\n\n
\n
    \n
  1. 否则,记录当前线程正在初始化 C 的 Class 对象,并释放 LC。\n 然后,初始化 C 的静态字段,即常量变量 (\xc2\xa74.12.4, \xc2\ xa78.3.2、\xc2\xa79.3.1)。
  2. \n
\n\n

(其他步骤在这里)

\n\n
    \n
  1. 接下来,按文本顺序执行类变量初始值设定项和类的静态初始值设定项,或接口的字段初始值设定项,就好像它们是单个块一样。
  2. \n
\n
\n\n

因此,INSTANCE在文本上首先列出,在listmap和之前name。为什么三个都还没动呢null?这是因为name是由常量表达式初始化的;它是一个常量变量。它首先被初始化,before INSTANCE,因为它是一个常量变量。

\n\n

请注意,您可以将初始化行移到andINSTANCE之后,从而使和在之前初始化。listmaplistmapINSTANCE

\n