【发布时间】:2014-05-11 04:48:46
【问题描述】:
考虑以下代码:
public final class Foo {
private static final Random random = new Random();
private Foo() {}
}
这个类不能被实例化所以,什么时候初始化random?
【问题讨论】:
标签: java static initialization final
考虑以下代码:
public final class Foo {
private static final Random random = new Random();
private Foo() {}
}
这个类不能被实例化所以,什么时候初始化random?
【问题讨论】:
标签: java static initialization final
静态字段在类初始化期间被初始化,例如这里
...
Class.forName("test.Foo");
...
加载JVM后会初始化random字段,不会创建Foo实例。为了测试它,我们可以像这样改变 Foo
class Foo {
private static final Random random = new Random() {
{
System.out.println("random initialized");
}
};
...
【讨论】:
forName() 显式初始化了一个新对象。所以这仍然是在技术上创建一个新的Foo。使用Class.forName("test.Foo", false, Class.class.getClassLoader()) 不会初始化Foo。
Class.forName("test.Foo") 不会创建 test.Foo 的新实例。
根据Java Language Specification section 12.4,静态成员和块的初始化发生在类初始化期间。初始化类的确切时间和这样做的步骤可以在链接中找到;一般来说,类在第一次以任何方式被访问时都会被加载/初始化,而加载/初始化包括静态成员的创建。
但是,如果这就是 Foo 的全部内容,我不相信 random 会被初始化,因为它不能被实例化,它的静态成员不能被访问,也不能被子类化。根据 JLS 第 12.4.1 节,在这些情况下会发生初始化:
T 是一个类,并创建了一个 T 的实例。
T是一个类,调用了T声明的静态方法。
分配了一个由 T 声明的静态字段。
使用了由 T 声明的静态字段,并且该字段不是常量变量(第 4.12.4 节)。
T 是一个顶级类(第 7.6 节),并执行一个词法嵌套在 T(第 8.1.3 节)中的断言语句(第 14.10 节)。
Foo 没有静态方法,所以不能发生。 3. 不能发生,因为静态字段是私有的。 4. 不能发生,因为静态字段是私有的,所以不能使用。 5. 不能发生,因为没有断言语句。所以我认为random 永远不会被初始化,因为 OP 的代码就是全部(编辑:除非你使用反射)
【讨论】:
public int getRandomInt(){ return random.nextInt(); }这样的getter
Foo。但是发布的 OP 代码永远不会导致 random 被初始化。