谁调用了类初始化方法<clinit>以及何时?</clinit>

时间:2013-04-10 07:13:52

标签: java jvm bytecode

我知道 dup invokespecial astore 字节码模式将调用实例初始化方法<init>当有人从Java语言的角度来看Java类时,但我从来没有弄清楚是谁调用了特殊的<clinit>方法,这是什么时候发生的?

我的猜测是<clinit><init>方法之前被调用。任何机构都可以给我一些信息来证明吗?这是在JVM规范还是Java语言规范中记录的?

3 个答案:

答案 0 :(得分:7)

JVM规范§2.9. Special Methods

  

类或接口最多只有一个类或接口初始化方法,并通过调用该方法进行初始化(第5.5节)。类或接口的初始化方法具有特殊名称<clinit>,不带参数,并且是无效的(§4.3.3)。

     

名称<clinit>由编译器提供。因为名称不是有效的标识符,所以它不能直接用在用Java编程语言编写的程序中。 Java虚拟机隐式调用类和接口初始化方法;它们永远不会直接从任何Java虚拟机指令调用,但只能作为类初始化过程的一部分间接调用。

有关类初始化过程的更多详细信息,请参阅Chapter 5

答案 1 :(得分:6)

<clinit>是javac添加的静态方法,在类加载后由JVM调用。我们可以使用字节码大纲工具在类字节码中看到这个方法。请注意,仅当类需要静态初始化时才添加<clinit>,例如

public class Test1 {
    static int x  = 1; 

    public static void main(String[] args) throws Exception {
    }
}

public class Test2 {
    static final int x  = 1; 

    public static void main(String[] args) throws Exception {
    }
}

Test1有<clinit>,因为其字段x需要初始化为1;而Test2没有<clinit>方法,因为它的x是常量。

有趣的是,Class.forNameboolen intialize param,用于确定是否应在加载后初始化类。

答案 2 :(得分:1)

<clinit>是类的静态初始化块,静态字段初始化及其由JVM调用。

Java Spec说, http://java.sun.com/docs/books/jvms/second_edition/html/Overview.doc.html#12174

The initialization method of a class or interface is static and takes no arguments. It has the special name <clinit>. This name is supplied by a compiler. Because the name <clinit> is not a valid identifier, it cannot be used directly in a program written in the Java programming language. Class and interface initialization methods are invoked implicitly by the Java virtual machine