你可以在这两个静态字段上设置字段断点来验证发生了什么。
我稍微修改了你的示例:
class TariffModelManager {
private static final TariffModelManager tariffModelManager = TariffModelManager.getInstance();
private static volatile TariffModelManager _instance = new TariffModelManager();
private TariffModelManager() {
System.out.println("From Constructor: " + this);
}
public static TariffModelManager getInstance() {
if (_instance == null) {
synchronized (TariffModelManager.class) {
if (_instance == null) {
_instance = new TariffModelManager();
System.out.println("Creating new instance: " + _instance);
}
}
}
return _instance;
}
public static void main(String[] args) {
TariffModelManager.getInstance();
System.out.println("tariffModelManager: " + TariffModelManager.tariffModelManager);
System.out.println("_instance: " + TariffModelManager._instance);
}
}
这里是输出:
From Constructor: TariffModelManager@ea4a92b
Creating new instance: TariffModelManager@ea4a92b
From Constructor: TariffModelManager@3c5a99da
tariffModelManager: TariffModelManager@ea4a92b
_instance: TariffModelManager@3c5a99da
静态字段tariffModelManager
会首先被初始化。当调用getInstance
方法时,_instance
为null,即默认值还未初始化。然后它会在该方法内部进行初始化,并将值分配给tariffModelManager
。接下来,根据静态初始化顺序再次重新初始化:接下来,按照文本顺序执行类变量初始化器和静态初始化器,或接口的字段初始化器,就像它们是一个单独的块一样。
这很有趣,因为
class TariffModelManager {
private static final TariffModelManager tariffModelManager = _instance;
private static volatile TariffModelManager _instance = new TariffModelManager();
private TariffModelManager() {
System.out.println("From Constructor: " + this);
}
public static TariffModelManager getInstance() {
return _instance;
}
}
虽然Java中无效,但静态方法提供了一种“解决”它的方法(即tariffModelManager将为null,不是真正预期的结果,但仍然可以编译):
class TariffModelManager {
private static final TariffModelManager tariffModelManager = getInstance();
private static volatile TariffModelManager _instance = new TariffModelManager();
private TariffModelManager() {
System.out.println("From Constructor: " + this);
}
public static TariffModelManager getInstance() {
return _instance;
}
}
TariffModelManager.getInstance()
的主方法时,它就会这样做。 - RobertgetInstance()
方法,并且存在同步屏障以防止多个并发初始化。