通过枚举方式单例是懒惰初始化?
这是一个非常广泛的枚举单例代码:
public enum enumClazz{
INSTANCE
enumClazz(){
//do something
}
}
和一堆地方说这是一个懒惰的初始化。 但是当我阅读'Java虚拟机内部'的第7章时,我感到困惑 - 一种类型的生命周期:
Java虚拟机规范为实现类和接口加载和链接的时机提供了灵活性,但严格定义了初始化的时间。 所有实现都必须初始化每个类或接口的第一次活动用途。 以下六种情况有资格作为主动使用:
第三点以粗体显示,如果该字段是static final
字段,则该字段的初始化将在编译时发生。 同样, enumClazz
的INSTANCE
隐含地等于public static final
并符合第三点。
如果我的理解错误,有人能纠正我吗?
enum
实例字段不是“由编译时常量表达式初始化”。 它们不可以,因为只有String
和原始类型是编译时常量表达式的可能类型。
这意味着当INSTANCE
第一次被访问时,这个类将被初始化(这正是所期望的效果)。
在上面的粗体文本中存在异常,因为在编译期间这些常量(使用编译时常量表达式初始化的static final
字段)将在编译期间有效地内联:
class A {
public static final String FOO = "foo";
static {
System.out.println("initializing A");
}
}
class B {
public static void main(String[] args) {
System.out.println(A.FOO);
}
}
在这个例子中执行类B
不会初始化A
(并且不会打印“初始化A”)。 如果您查看为B
生成的字节码,您将看到一个字符串文本,其值为“foo”,并且没有对类A
引用。
大胆的第三点澄清,如果该字段是“静态最终”字段的初始化发生在编译时
不完全 - 它只适用于“最终由编译时常量表达式初始化的静态字段”:
static final String = "abc"; //compile time constant
static final Object = new Object(); //initialised at runtime
在你的情况下,单例将在enum类被加载时初始化,也就是说第一次在代码中引用enumClazz
。
所以它是有效的懒惰,除非你在你的代码中有这样的代码,例如,这会不必要地将你的单例初始化为类加载过程的一部分:
Class<?> c = enumClazz.class;
链接地址: http://www.djcxy.com/p/78833.html