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
typename
变量是一个编译时常量,编译器在编译时将其内联。因此,条件:
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)