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

Java 类中的静态字段初始化序列,java,static,Java,Static,当一个类本身有一个静态实例时,我很难理解初始化顺序。还有,为什么字符串的这种行为似乎不同 请参见以下示例: public class StaticCheck { private static StaticCheck INSTANCE = new StaticCheck(); private static final List<String> list = new ArrayList<String>(Arrays.asList("h

当一个类本身有一个静态实例时,我很难理解初始化顺序。还有,为什么
字符串的这种行为似乎不同

请参见以下示例:

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();
    }
}
我完全不清楚为什么
name
字段不为空。 静态字段在以下情况下初始化,如类初始化中所述:

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

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

  • 在上面的示例中,由于字段
    实例
    是静态的,因此当其他字段未初始化时,它的对象初始化发生,并且它的构造函数调用
    load()
    。因此,
    list
    map
    字段为空。那么为什么
    name
    被初始化了呢?我有点困惑


  • String
    type
    name
    变量是一个编译时常量,编译器在编译时将其内联。因此,条件:

    if (name != null)
    
    汇编后将成为:

    if ("hello" != null)
    
    这当然是真的


    至于为什么
    map
    list
    null
    ,那是因为初始化类时,
    实例
    字段被初始化,调用构造函数,构造函数反过来调用
    load()
    方法。请注意,此时,其他
    静态
    初始值设定项尚未运行。所以,
    map
    list
    仍然是
    null
    。因此,在
    load()
    方法中打印它们将是
    null

    在初始化任何非
    静态
    变量之前初始化常量
    静态
    变量。中说明了类的初始化过程:

  • 否则,记录当前线程正在初始化C的类对象,并释放LC。 然后,初始化C的静态字段,这些字段是常量变量(§4.12.4、§8.3.2、§9.3.1)
  • (此处为其他步骤)

  • 接下来,按照文本顺序执行类的类变量初始值设定项和静态初始值设定项,或者执行接口的字段初始值设定项,就像它们是单个块一样
  • 因此,
    实例
    列表
    映射
    名称
    之前以文本形式首先列出。为什么3个都不是空的?这是因为
    name
    由常量表达式初始化;它是一个常量变量。它首先初始化,在
    实例
    之前,因为它是一个常量变量


    请注意,您可以在
    列表
    映射
    之后移动初始化
    实例
    的行,使
    列表
    映射
    实例
    之前初始化,编译时只会分配原语类型和
    字符串
    ,并且仅当字段为
    final
    并使用文字或常量表达式初始化时。所有其他
    静态
    字段和块稍后将按顺序计算。请参见此示例:

    公共类静态示例{
    私有静态StaticExample instance1=新的StaticExample(1);
    公共静态void main(字符串[]args){
    新示例(3);
    }
    公共静态布尔值b=true;
    公共静态最终布尔值fb=true;
    公共静态布尔值B=true;
    公共静态最终布尔值fB=true;
    公共静态字符串S=“text”;
    公共静态最终字符串fS=“text”;
    公共静态最终字符串cS=“te”+“xt”;//常量表达式
    公共静态最终字符串xS=fS.substring(0,2)+fS.substring(2,4);
    private static StaticExample instance2=新的StaticExample(2);
    私有静态示例(int no){
    System.out.println(“##“+no+”:##”);
    System.out.println(“b:+b”);
    System.out.println(“fb:+fb”);
    System.out.println(“B:+B”);
    System.out.println(“fB:+fB”);
    System.out.println(“S:+S”);
    System.out.println(“fS:+fS”);
    System.out.println(“cS:+cS”);
    System.out.println(“xS:+xS”);
    System.out.println();
    }
    }
    
    输出:

    ##1:##
    b:错
    fb:是的
    B:空
    fB:null
    S:空
    财政司司长:文本
    政务司司长:文本
    xS:null
    ## 2: ##
    b:是的
    fb:是的
    B:是的
    fB:是的
    S:文本
    财政司司长:文本
    政务司司长:文本
    xS:text
    ## 3: ##
    b:是的
    fb:是的
    B:是的
    fB:是的
    S:文本
    财政司司长:文本
    政务司司长:文本
    xS:text
    

    fb
    是一个最终原语,
    fS
    cS
    是常量最终字符串,只有这三个字段是预先指定的。

    你能把你的答案扩展到问题的第一部分吗?乍一看可能不那么明显。@Turing85对此进行了解释。为了给你们一个提示,你们链接到的那篇文章说“类是从上到下初始化的,所以在顶部声明的字段在底部声明的字段之前初始化”。这对于示例的行为非常重要。
    if ("hello" != null)