[英]Java initialization order issue, static vs instance fields
The program below prints: 以下程序打印:
my name is:null
my name is:null
Someclass static init
AFAIK when a class is first loaded static blocks and fields are always initialized first, instance blocks and fields second. 首次加载类时的AFAIK静态块和字段始终首先被初始化,实例块和字段被初始化。 Therefore variables "objectName1" and "objectName2" should be initialized first, instance variable "list" second...but the ouput obviously contradicts this theory... Can anyone explain the program behavior (I'm not looking for a critique of the design in itself btw) ?
因此变量“objectName1”和“objectName2”应该首先被初始化,实例变量“list”第二......但是输出明显与这个理论相矛盾...任何人都可以解释程序行为(我不是在寻找对它的批评设计本身btw)?
import java.util.ArrayList;
import java.util.List;
public class Main2{
public static void main (String[] args){
SomeClass.getInstance();
}
}
class SomeClass {
private static final SomeClass instance = new SomeClass();
public static SomeClass getInstance(){
return instance;
}
static {
System.out.println ("Someclass static init");
}
private static String objectName1 ="test1";
private static String objectName2 ="test2";
@SuppressWarnings("serial")
private List<SomeObject> list=
new ArrayList<SomeObject> () { {
add (new SomeObject(objectName1));
add (new SomeObject(objectName2));
}};
}
class SomeObject {
String name;
SomeObject (String name){
this.name = name;
System.out.println ("my name is:" +name);
}
}
Static blocks are initialized in order (so you can rely on the ones above in the ones below). 静态块按顺序初始化(因此您可以依赖上面的那些)。 By creating an instance of
SomeClass
as your first static initializer in SomeClass
, you're forcing an instance init during the static init phase. 通过创建实例
SomeClass
作为你的第一个静态初始化SomeClass
,你在静态初始化阶段迫使初始化一个实例。
So the logical order of execution of your code is: 因此,代码执行的逻辑顺序是:
SomeClass
, all static fields initially defaults ( 0
, null
, etc.) SomeClass
,所有静态字段最初默认为( 0
, null
等) SomeClass
SomeClass
实例 SomeClass
instance, using current values for static fields (so objectName1
and objectName2
are null
) SomeClass
实例的实例内容(因此objectName1
和objectName2
为null
) SomeObject
class, all static fields initially default (you don't have any) SomeObject
类,所有静态字段最初默认(你没有) SomeObject
static inits (you don't have any) SomeObject
静态SomeObject
(你没有) SomeObject
using the passed-in null
values null
值创建SomeObject
实例 SomeClass
, setting objectName1
and objectName2
SomeClass
静态内容,设置objectName1
和objectName2
To make this work as you may expect, simply put the inits for objectName1
and objectName2
above the init for instance
. 为了使这项工作,你可能期望的那样,简单地把对inits
objectName1
和objectName2
初始化以上instance
。
As suggested moving this line: 正如建议移动这一行:
private static final SomeClass instance = new SomeClass();
after these: 在这之后:
private static String objectName1 ="test1";
private static String objectName2 ="test2";
should fix the problem. 应该解决问题。
On first look I was pretty surprised about the behavior myself, but on second thought, it is quite trivial to explain: 初看起来我对自己的行为感到非常惊讶,但是第二个想法,解释起来是非常简单的:
private static final SomeClass instance = new SomeClass();
is part of the static initialization of SomeClass
. 是
SomeClass
的静态初始化的一部分。 As you create an instance before initialization has completed, the class is not yet completely initialized. 在初始化完成之前创建实例时,该类尚未完全初始化。 When you replace the
System.out.println(...);
当您替换
System.out.println(...);
with something like new Exception().printStackTrace();
有一些像
new Exception().printStackTrace();
you get this (note that I put all classes as static nested classes into Main) 你得到这个(注意我把所有类作为静态嵌套类放入Main)
at Main$SomeObject.<init>(Main.java:37) // new Exception().printStackTrace();
at Main$SomeClass$1.<init>(Main.java:26) // add(new SomeObject(...))
at Main$SomeClass.<init>(Main.java:23) // list = new ArrayList()
at Main$SomeClass.<clinit>(Main.java:10) // instance = new SomeClass()
at Main.main(Main.java:6) // SomeClass.getInstance();
As you see, execution still is inside Main$SomeClass.<clinit>
(the class initialization), hence SomeClass is not completely initialized. 如您所见,执行仍然在
Main$SomeClass.<clinit>
(类初始化)中,因此SomeClass未完全初始化。
As a side note: the best way to implement Singleton pattern is to avoid it completely. 作为旁注:实现Singleton模式的最佳方法是完全避免它。 The second best most likely is using
enum
(at least it's Josh-Bloch-approved) 第二个最有可能是使用
enum
(至少它是Josh-Bloch批准的)
class enum SomeClass {
instance;
// snip
}
The first thing that executes is probably the static initializer of the instance
variable. 执行的第一件事可能是
instance
变量的静态初始化程序。 This causes the list to be initialized using the (uninitialized) objectName1
and objectName2
variables. 这会导致使用(未初始化的)
objectName1
和objectName2
变量初始化列表。 After that, it proceeds to initialize objectName1
and objectName2
. 之后,它继续初始化
objectName1
和objectName2
。
If you move the declaration of instance
to the end of SomeClass
it will probably do what you're expecting. 如果将
instance
的声明移动到SomeClass
的末尾,它可能会执行您期望的操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.