Java: Яка різниця між <init> та <clinit>?


94

Я не можу зрозуміти наступний текст ... Чи означає це, що <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, а викликаються лише опосередковано як частина процесу ініціалізації класу.

Відповіді:


142

<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/…
Кейд Даніель

@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.