Java: Sự khác biệt giữa <init> và <clinit> là gì?


94

Tôi không thể hiểu văn bản sau ... Nó có nghĩa là nó <clinit>dành cho các hàm tạo trống? Tại sao lại quan trọng phải có hai phiên bản khác nhau?

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

2.9. Special Methods

Ở cấp độ của máy ảo Java, mọi phương thức khởi tạo (§2.12) xuất hiện như một phương thức khởi tạo thể hiện có tên đặc biệt <init>. Tên này được cung cấp bởi một trình biên dịch. Bởi vì tên <init>không phải là một định danh hợp lệ, nó không thể được sử dụng trực tiếp trong một chương trình được viết bằng ngôn ngữ lập trình Java. Các phương thức khởi tạo phiên bản chỉ có thể được gọi trong máy ảo Java bằng lệnh gọi đặc biệt và chúng chỉ có thể được gọi trên các cá thể lớp chưa được khởi tạo. Một phương thức khởi tạo thể hiện nhận quyền truy cập (§2.7.4) của phương thức khởi tạo mà từ đó nó được dẫn xuất.

Một lớp hoặc giao diện có nhiều nhất một phương thức khởi tạo lớp hoặc giao diện và được khởi tạo (§2.17.4) bằng cách gọi phương thức đó. Phương thức khởi tạo của một lớp hoặc giao diện là tĩnh và không có đối số. Nó có cái tên đặc biệt <clinit>. Tên này được cung cấp bởi một trình biên dịch. Bởi vì tên <clinit>không phải là một định danh hợp lệ, nó không thể được sử dụng trực tiếp trong một chương trình được viết bằng ngôn ngữ lập trình Java. Các phương thức khởi tạo lớp và giao diện được gọi ngầm bởi máy ảo Java; chúng không bao giờ được gọi trực tiếp từ bất kỳ máy ảo Java nào trongw2struction, mà chỉ được gọi gián tiếp như một phần của quá trình khởi tạo lớp.

Câu trả lời:


142

<init> là (hoặc một trong các) phương thức khởi tạo cho phiên bản và khởi tạo trường không tĩnh.

<clinit> là các khối khởi tạo tĩnh cho lớp và khởi tạo trường tĩnh.

class X {

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

   private int x = 1;   // <init>

   X(){
      // <init>
   }

   static {
      // <clinit>
   }

}


14
Tôi đoán là "đẳng cấp".
Thilo

2
@Thilo điều đó thật thú vị vì JVM cũng coi định nghĩa lớp như một kiểu đối tượng khác.
Jonathan Neufeld

@JonathanNeufeld true, mặc dù tôi nghĩ rằng có một số quy tắc đặc biệt. Phương pháp này (gọi tắt là bởi lớp initializer) được đánh dấu là có nguồn gốc ... grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/...
Cade Daniel

@Thilo nó cũng có thể là viết tắt của "ClassLoader".
Duncan Calvert


13

Sự khác biệt giữa <init><clinit><init>được sử dụng cho các phương thức khởi tạo khởi tạo một cá thể đối tượng, trong khi <clinit>được sử dụng để khởi tạo chính đối tượng lớp. Ví dụ, khởi tạo bất kỳ statictrường cấp độ lớp nào được thực hiện <clinit>khi lớp đó được tải và khởi tạo.


1

Chỉ để thêm Nếu bạn sử dụng phương thức Class.forName, nó chỉ intialize lớp. Vì vậy, từ bên trong phương thức này, nó chỉ thực hiện một cuộc gọi đến clinit và khi bạn sử dụng newInstance trên đối tượng được trả về từ forName, nó sẽ gọi init để khởi tạo phiên bản. Bạn có thể sử dụng mã bên dưới để xem nó trong gỡ lỗi.

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");
 }

Để kiểm tra, hãy sử dụng

   Class<ByteCodeParent> bcp2 =(Class<ByteCodeParent>) Class.forName("ByteCodeParent");
ByteCodeParent bcp4= bcp2.newInstance();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.