Кто вызывает метод инициализатора класса и когда?

Я знаю, что новая, dup, invokespecial и Асторе шаблон байт-кода вызовет метод инициализатора экземпляра <init> когда кто-то экземпляр класса Java с точки зрения языка Java, но я никогда не понимаю, кто вызывает специальный <clinit>способ и когда это происходит?

Я предполагаю, что <clinit> вызывается до <init> метод. Может кто-либо дать мне некоторую информацию доказать? Это задокументировано в спецификации JVM или спецификации языка Java?

3 ответов


спецификация JVM §2.9. Специальные Методы:

класс или интерфейс имеет не более одного метода инициализации класса или интерфейса и инициализируется (§5.5) путем вызова этого метода. Метод инициализации класса или интерфейса имеет специальное имя <clinit>, не принимает никаких аргументов, и является недействительным (§4.3.3).

имя <clinit> поставляется компилятор. Поскольку имя не является допустимым идентификатором, его нельзя использовать непосредственно в написанной программе на языке программирования Java. класса и инициализации методы вызываются неявно виртуальной машиной Java; они никогда не вызываются непосредственно ни от какой инструкции виртуальной машины Java, но вызываются косвенно как часть процесса инициализации класса.

посмотреть Глава 5 для получения дополнительной информации о процессе инициализации класса.


<clinit> - статический метод, добавленный javac и вызываемый JVM после загрузки класса. Мы можем видеть этот метод в байт-коде класса с инструментами контура байт-кода. Обратите внимание, что <clinit> добавляется, только если класс нуждается в статической инициализации, e.g

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.forName и boolen intialize param который определяет, должен ли класс быть инициализирован после загрузки или нет.


<clinit> являются статическими блоками инициализации для класса, а также инициализацией статического поля и его вызовом JVM.

спецификация Java говорит, 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