2

问题是关于Java的。获取一个类型的类有三种方式(注意,代码只是演示的片段集合):

Class c1 = Class.forName("com.mypkg.MyClass"); //assumes initialize = true
// - OR - 
Class c1 = Class.forName("com.mypkg.MyClass", true/false,
                         this.getClass().getClassLoader());

Class c2 = com.mypkg.MyClass.class;
// - OR - 
import com.mypkg.MyClass;
Class c2 = MyClass.class;

MyClass mc = new MyClass();
Class c3 = mc.getClass();

我的问题是关于初始化。对于方法 1,我可以使用布尔参数控制类是否被初始化。对于方法3,由于创建了一个对象,显然该类已初始化(对吗?)。

但是方法2呢?.class如果尚未初始化,调用是否会初始化该类?
以及如何以编程方式检查一个类是否已经初始化?

总结答案:

请参阅已接受的解决方案及其评论以获取完整答案。这只是一个总结。

如果尚未初始化,则调用.class不会初始化该类。您可以通过在打印消息的类定义中使用静态块来检查类是否正在初始化。

原始问题的原因:

根据 javadoc Class.forName“调用 forName("X") 会导致初始化名为 X 的类。” . 还有两种Class.forName方法,包括一种接受名为initialize的布尔参数的方法。根据 javadoc,“只有当 initialize 参数为真并且之前没有初始化时,才会初始化该类。”

4

2 回答 2

6

自己测试一下,看看你的虚拟机做了什么?

只需将此类与所有三种方法一起使用(在独立运行中,因为它最多只会初始化一次!)

class Example {
    static {
        System.out.println("Class was initialized!");
    }

    public static int bananas = 0;
}

有关应该初始化类的详细信息,请参阅http://docs.oracle.com/javase/specs/#12.4.1

粗略地说,一个类应该在以下任一情况下被初始化

  • 第一个实例被创建
  • 调用了一个static方法
  • 使用了非最终static字段
  • 一些更复杂的极端情况

所以本质上,当你第一次使用实际类的任何东西时,不仅仅是引用它。

但是例如Example.bananas = 1;也应该触发类初始化,而无需实例。

于 2012-12-06T08:45:02.227 回答
1

On the bytecode level, the reference to the class is loaded by the one of the ldc instructions. The VM specification does not mention that the classes are initialized, so the safe thing to say is probably that the VM does not guarantee that such a reference initializes the class, but do mind that the VM specification does not require a VM to do initialization as lazily as possible either.

The class may legally be initialized at any time between it being first referenced and initialization being strictly required.

于 2012-12-06T08:49:20.810 回答