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

Geo*_*rge 10 java jvm bytecode

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

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

NPE*_*NPE 7

JVM规范§2.9.特殊方法:

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

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

有关类初始化过程的更多详细信息,请参见第5章.


Evg*_*eev 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 {
    }
}
Run Code Online (Sandbox Code Playgroud)

Test1 <clinit>因为其字段x需要用1初始化; 而Test2没有<clinit>方法,因为它x是一个常数.

值得注意的是,Class.forName有一个boolen intializeparam可以确定是否应该在加载后初始化类.

  • “请注意,仅当一个类需要静态初始化时才添加 &lt;clinit&gt;”——任何来源? (2认同)