类中的java静态字段初始化序列
当一个类本身有一个静态实例时,我很难理解初始化顺序。还有,为什么这种行为对于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();
}
}
输出:
List is null
name is nonnull
Map is null
我完全不清楚为什么name
字段不是空的。
静态字段在以下情况下初始化,如类初始化中所述:
http://javarevisited.blogspot.in/2012/07/when-class-loading-initialization-java-example.html
看看上面的例子,我的想法是:
如上所述,在Java中,静态字段是在实例初始化之前初始化的。在这里,当我调用静态方法
getInstance()
时,它将导致类初始化,这意味着静态字段的初始化。在这种情况下,字段map
和list
不应为空在上面的示例中,由于字段
INSTANCE
是静态的,因此当其他字段未初始化时,它的对象初始化发生,并且它的构造函数调用load()
。因此list
和map
字段为空。那么为什么name
会被初始化呢?我有点困惑
# 1 楼答案
在初始化任何非
static
变量之前,先初始化常量static
变量。JLS, Section 12.4.2表示类的初始化过程:因此,
INSTANCE
在list
、map
和name
之前以文本形式列在第一位。为什么不是所有3个都是null
?这是因为name
由一个常量表达式初始化;它是一个常量变量。它首先被初始化,在INSTANCE
之前,因为它是一个常量变量请注意,您可以将初始化
INSTANCE
的行移动到list
和map
之后,导致list
和map
在INSTANCE
之前初始化# 2 楼答案
在编译时,只有基元类型和
String
会被赋值,并且只有当字段是final
并且用文本或常量表达式初始化时才会赋值。所有其他static
字段和块稍后将按顺序计算。看这个例子:输出:
fb
是最终原语,fS
和cS
是常量最终字符串,只有这三个字段是预先指定的# 3 楼答案
String
typename
变量是编译时常量,编译器在编译时将其内联。所以,条件是:汇编后将成为:
这当然是真的
至于为什么
map
和list
是null
,那是因为,初始化类时,INSTANCE
字段被初始化,调用构造函数,构造函数反过来调用load()
方法。请注意,此时,其他static
初始值设定项尚未运行。所以,map
和list
仍然是null
。因此,在load()
方法中打印它们将是null