class 中的静态字段初始化序列
Static field initialization sequence in a class
当 class 具有自身的静态实例时,我无法理解初始化顺序。此外,为什么这种行为对于 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
字段不为空。
Class 初始化中提到的静态字段在以下情况下被初始化:
http://javarevisited.blogspot.in/2012/07/when-class-loading-initialization-java-example.html
看了上面的例子,我的想法是:
如前所述,在 Java 中,静态字段在实例初始化之前被初始化。在这里,当我调用静态方法 getInstance()
时,它会导致 class 初始化,这意味着静态字段的初始化。在这种情况下,字段 map
和 list
不应为空。
在上面的例子中,由于字段INSTANCE
是静态的,它的对象初始化发生并且它的构造函数在其他字段没有初始化时调用load()
。因此,字段 list
和 map
为空。那么为什么 name
会被初始化呢?我有点糊涂了。
String
类型的name
变量是编译时常量,由编译器在编译时内联。所以,条件:
if (name != null)
编译后会变成:
if ("hello" != null)
这当然是真的。
至于为什么map
和list
是null
,那是因为在初始化class的时候,初始化了INSTANCE
字段,调用构造函数,它又调用 load()
方法。请注意,此时,其他 static
个初始值设定项尚未 运行。所以,map
和 list
仍然是 null
。因此,在 load()
方法中打印它们将是 null
.
常量 static
变量在初始化任何非 static
变量之前被初始化。 JLS, Section 12.4.2 说明了 class:
的初始化过程
- Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC.
Then, initialize the static fields of C which are constant variables (§4.12.4, §8.3.2, §9.3.1).
(other steps here)
- 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.
因此,INSTANCE
按文本顺序排在第一位,排在 list
、map
和 name
之前。为什么不是所有 3 个都仍然 null
?这是因为name
是由一个常量表达式初始化的;它是一个 常量变量 。它首先被初始化,在 INSTANCE
之前,因为它是一个常量变量。
请注意,您可以将初始化 INSTANCE
的行移动到 list
和 map
之后,导致 list
和 map
在 [=12] 之前初始化=].
只有原始类型和 String
会在编译时赋值,并且只有当字段是 final
并且用文字或常量表达式初始化时。所有其他 static
字段和块将在稍后按顺序进行评估。看这个例子:
public class StaticExample {
private static StaticExample instance1 = new StaticExample(1);
public static void main(String[] args) {
new StaticExample(3);
}
public static boolean b = true;
public static final boolean fb = true;
public static Boolean B = true;
public static final Boolean fB = true;
public static String S = "text";
public static final String fS = "text";
public static final String cS = "te" + "xt"; // constant expression
public static final String xS = fS.substring(0, 2) + fS.substring(2, 4);
private static StaticExample instance2 = new StaticExample(2);
private StaticExample(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: false
fb: true
B: null
fB: null
S: null
fS: text
cS: text
xS: null
## 2: ##
b: true
fb: true
B: true
fB: true
S: text
fS: text
cS: text
xS: text
## 3: ##
b: true
fb: true
B: true
fB: true
S: text
fS: text
cS: text
xS: text
fb
是final原语,fS
和cS
是constant final String,只有这三个字段是预赋值的。
当 class 具有自身的静态实例时,我无法理解初始化顺序。此外,为什么这种行为对于 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
字段不为空。
Class 初始化中提到的静态字段在以下情况下被初始化:
http://javarevisited.blogspot.in/2012/07/when-class-loading-initialization-java-example.html
看了上面的例子,我的想法是:
如前所述,在 Java 中,静态字段在实例初始化之前被初始化。在这里,当我调用静态方法
getInstance()
时,它会导致 class 初始化,这意味着静态字段的初始化。在这种情况下,字段map
和list
不应为空。在上面的例子中,由于字段
INSTANCE
是静态的,它的对象初始化发生并且它的构造函数在其他字段没有初始化时调用load()
。因此,字段list
和map
为空。那么为什么name
会被初始化呢?我有点糊涂了。
String
类型的name
变量是编译时常量,由编译器在编译时内联。所以,条件:
if (name != null)
编译后会变成:
if ("hello" != null)
这当然是真的。
至于为什么map
和list
是null
,那是因为在初始化class的时候,初始化了INSTANCE
字段,调用构造函数,它又调用 load()
方法。请注意,此时,其他 static
个初始值设定项尚未 运行。所以,map
和 list
仍然是 null
。因此,在 load()
方法中打印它们将是 null
.
常量 static
变量在初始化任何非 static
变量之前被初始化。 JLS, Section 12.4.2 说明了 class:
- Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC. Then, initialize the static fields of C which are constant variables (§4.12.4, §8.3.2, §9.3.1).
(other steps here)
- 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.
因此,INSTANCE
按文本顺序排在第一位,排在 list
、map
和 name
之前。为什么不是所有 3 个都仍然 null
?这是因为name
是由一个常量表达式初始化的;它是一个 常量变量 。它首先被初始化,在 INSTANCE
之前,因为它是一个常量变量。
请注意,您可以将初始化 INSTANCE
的行移动到 list
和 map
之后,导致 list
和 map
在 [=12] 之前初始化=].
只有原始类型和 String
会在编译时赋值,并且只有当字段是 final
并且用文字或常量表达式初始化时。所有其他 static
字段和块将在稍后按顺序进行评估。看这个例子:
public class StaticExample {
private static StaticExample instance1 = new StaticExample(1);
public static void main(String[] args) {
new StaticExample(3);
}
public static boolean b = true;
public static final boolean fb = true;
public static Boolean B = true;
public static final Boolean fB = true;
public static String S = "text";
public static final String fS = "text";
public static final String cS = "te" + "xt"; // constant expression
public static final String xS = fS.substring(0, 2) + fS.substring(2, 4);
private static StaticExample instance2 = new StaticExample(2);
private StaticExample(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: false
fb: true
B: null
fB: null
S: null
fS: text
cS: text
xS: null
## 2: ##
b: true
fb: true
B: true
fB: true
S: text
fS: text
cS: text
xS: text
## 3: ##
b: true
fb: true
B: true
fB: true
S: text
fS: text
cS: text
xS: text
fb
是final原语,fS
和cS
是constant final String,只有这三个字段是预赋值的。