Кто вызывает метод инициализатора класса <clinit> и когда?
Я знаю, что в шаблоне байт-кода новый, dup, invokespecial и astore будет вызываться метод инициализации экземпляра <init>
, когда кто-то экземпляр класса Java с точки зрения языка Java, но я никогда не понимаю, кто вызывает специальный метод <clinit>
, и когда это происходит?
Я предполагаю, что <clinit>
вызывается методом до <init>
. Может ли какой-нибудь орган дать мне некоторую информацию, чтобы доказать это? Является ли это документировано в спецификации JVM или спецификации языка Java?
Ответы
Ответ 1
JVM spec §2.9. Специальные методы:
Класс или интерфейс имеет не более одного метода инициализации класса или интерфейса и инициализируется (§5.5), вызывая этот метод. Метод инициализации класса или интерфейса имеет специальное имя <clinit>
, не принимает аргументов и недействителен (§4.3.3).
Имя <clinit>
предоставляется компилятором. Поскольку имя не является допустимым идентификатором, его нельзя использовать непосредственно в программе, написанной на языке программирования Java. Методы инициализации класса и интерфейса вызываются неявно с помощью виртуальной машины Java; они никогда не вызывается непосредственно из любой инструкции Java Virtual Machine, а вызываются только косвенно как часть процесса инициализации класса.
Подробнее о процессе инициализации класса см. Глава 5.
Ответ 2
<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.forName
имеет параметр boolen intialize
, который определяет, должен ли класс инициализироваться после загрузки или нет.
Ответ 3
<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