“ .class”获取Class的方式,它是否会初始化类?

3

这个问题涉及到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不会初始化类,如果要检查类是否正在初始化,可以在类定义中使用静态块打印消息。
原始问题的原因:
根据Class.forName的javadoc,“调用forName(“X”)会导致名为X的类被初始化。”此外,有两种Class.forName方法,其中包括一种接受名为initialize的布尔参数。根据javadoc,“仅当initialize参数为true且尚未初始化时才初始化该类”。

加载时的初始化? - undefined
c1、c2、c3是Class类型的对象,而不是已初始化的类。 - undefined
1
@ivanovic 当我查阅 Class.forName 的 javadoc 时,它说:"调用 forName("X") 会导致名为 X 的类被初始化。" 此外,有两个 Class.forName 方法,其中一个接受一个布尔参数。根据 javadoc,"只有当 initialize 参数为 true 且该类尚未被初始化时,才会进行初始化。" 所以如果你说类不被初始化,这里的初始化是什么意思呢?顺便说一下,我正在使用 JVM 1.6。 - undefined
@ice 我知道这一点。问题是 .class 是否会引起类的初始化,就像 Class.forName 一样。 - undefined
1
@ivanovic 如果你愿意阅读Java文档中的Class.forName,它会提到"初始化"。类被初始化时,这可能指的是初始化static变量和执行static代码块。 - undefined
2个回答

7

你可以自己测试一下,看看你的虚拟机会做些什么?

只需使用这个类和其中的三个方法(在独立运行中使用,因为它最多只会初始化一次!)

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

    public static int bananas = 0;
}

要了解类何时被初始化的详细信息,请参见http://docs.oracle.com/javase/specs/#12.4.1

粗略地说,当满足以下条件之一时,类应该被初始化:

  • 创建第一个实例
  • 调用静态方法
  • 使用非final的静态字段
  • 更复杂的角落情形

因此,实际类的任何内容首次被使用时,都应该触发其初始化。

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


啊,你回答了我的第二个问题 :) 嗯,有点儿 :D - undefined
我使用了你的方法进行了一次测试,结果发现,在我使用MyClass.class获取类对象时,该类并没有被初始化。只有在随后执行c2.newInstance()时(前提是它之前从未被初始化过),它才会被初始化。非常感谢! - undefined

1

在字节码级别上,类的引用是通过ldc指令之一加载的。虚拟机规范没有提到类是否被初始化,所以可以安全地说,虚拟机不保证这样的引用会初始化类,但请注意,虚拟机规范也不要求虚拟机尽可能地惰性初始化。

类可以在第一次引用和强制要求初始化之间的任何时间合法地进行初始化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接