Java: в чем разница между <init> и <clinit>?


95

Я не понимаю следующий текст ... Означает ли это, что <clinit>это для пустых конструкторов? Почему важно иметь две разные версии?

https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html

2.9. Special Methods

На уровне виртуальной машины Java каждый конструктор (§2.12) появляется как метод инициализации экземпляра со специальным именем <init>. Это имя предоставляется компилятором. Поскольку имя <init>не является допустимым идентификатором, его нельзя использовать непосредственно в программе, написанной на языке программирования Java. Методы инициализации экземпляра могут быть вызваны только внутри виртуальной машины Java с помощью специальной инструкции invokespecial, и они могут быть вызваны только для неинициализированных экземпляров класса. Метод инициализации экземпляра принимает права доступа (§2.7.4) конструктора, от которого он был получен.

Класс или интерфейс имеет не более одного метода инициализации класса или интерфейса и инициализируется (§2.17.4) путем вызова этого метода. Метод инициализации класса или интерфейса является статическим и не принимает аргументов. У него особое название <clinit>. Это имя предоставляется компилятором. Поскольку имя <clinit>не является допустимым идентификатором, его нельзя использовать непосредственно в программе, написанной на языке программирования Java. Методы инициализации класса и интерфейса неявно вызываются виртуальной машиной Java; они никогда не вызываются напрямую из какой-либо виртуальной машины Java inw2struction, а вызываются только косвенно как часть процесса инициализации класса.

Ответы:


143

<init> - конструктор (или один из них) для экземпляра и инициализация нестатического поля.

<clinit> - блоки статической инициализации для класса и инициализация статического поля.

class X {

   static Log log = LogFactory.getLog(); // <clinit>

   private int x = 1;   // <init>

   X(){
      // <init>
   }

   static {
      // <clinit>
   }

}


14
Думаю, "класс".
Тило

2
@Thilo, что интересно, потому что JVM рассматривает определение класса как еще один тип объекта.
Джонатан Нойфельд

@JonathanNeufeld правда, хотя я думаю, что есть некоторые особые правила. Этот метод (вызываемый инициализатором класса) помечен как собственный ... grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
Cade Daniel

@Thilo также может означать "ClassLoader".
Дункан Калверт


13

Разница между <init>и <clinit>заключается в том, что <init>он используется для методов конструктора, которые инициализируют экземпляр объекта, тогда как <clinit>он используется для инициализации самого объекта класса. Например, инициализация любых staticполей уровня класса выполняется, <clinit>когда класс загружается и инициализируется.


1

Просто чтобы добавить. Если вы используете метод Class.forName, он только инициализирует класс. Таким образом, изнутри этого метода он вызывает только Clinit, а когда вы используете newInstance для объекта, возвращенного из forName, он вызывает init для инициализации экземпляра. Вы можете использовать приведенный ниже код, чтобы увидеть его при отладке.

public class ByteCodeParent
{
 public static String name="ByteCode";
 public ByteCodeParent()
{
    System.out.println("In Constructor");
}

 static
 {
     System.out.println("In Static");
 }

 {
     System.out.println("In Instance");
 }

Чтобы проверить, используйте

   Class<ByteCodeParent> bcp2 =(Class<ByteCodeParent>) Class.forName("ByteCodeParent");
ByteCodeParent bcp4= bcp2.newInstance();
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.