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 พวกเขาจะไม่ถูกเรียกโดยตรงจาก inw2struction เครื่องเสมือน Java ใด ๆ แต่จะถูกเรียกโดยทางอ้อมเท่านั้นซึ่งเป็นส่วนหนึ่งของกระบวนการเริ่มต้นคลาส

คำตอบ:


143

<init> เป็นตัวสร้าง (หรือหนึ่งใน) สำหรับอินสแตนซ์และการกำหนดค่าเริ่มต้นฟิลด์แบบไม่คงที่

<clinit> คือบล็อกการเริ่มต้นแบบคงที่สำหรับคลาสและการกำหนดค่าเริ่มต้นฟิลด์แบบคงที่

class X {

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

   private int x = 1;   // <init>

   X(){
      // <init>
   }

   static {
      // <clinit>
   }

}

5
ย่อมาจากอะไรCL?
Ciro Santilli 郝海东冠状病六四事件法轮功

14
ฉันเดาว่า "ชั้น"
Thilo

2
@ Thilo นั้นน่าสนใจเพราะ JVM ถือว่านิยามคลาสเป็นอ็อบเจ็กต์ประเภทอื่นเช่นกัน
Jonathan Neufeld

@JonathanNeufeld จริงแม้ว่าฉันคิดว่ามีกฎพิเศษบางอย่าง วิธีนี้ (เรียกโดย class initializer) ถูกทำเครื่องหมายเป็น native … grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/
Cade Daniel

@Thilo ยังสามารถยืนสำหรับ "ClassLoader"
Duncan Calvert


13

ความแตกต่างระหว่าง<init>และ<clinit>คือที่<init>ใช้สำหรับเมธอดตัวสร้างที่เริ่มต้นอินสแตนซ์อ็อบเจ็กต์ในขณะที่<clinit>ใช้เพื่อเริ่มต้นอ็อบเจ็กต์คลาสเอง ตัวอย่างเช่นการเริ่มต้นของstaticฟิลด์ระดับคลาสใด ๆจะกระทำ<clinit>เมื่อคลาสถูกโหลดและ initalised


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();
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.