Java:<init>和<clinit>有什么区别?


93

我无法理解以下文本...这是否意味着<clinit>空的构造函数?为什么拥有两个不同的版本很重要?

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

2.9. Special Methods

在Java虚拟机级别,每个构造函数(第2.12节)都作为具有特殊名称的实例初始化方法出现<init>。该名称由编译器提供。因为该名称<init>不是有效的标识符,所以不能直接用Java编程语言编写的程序中使用它。实例初始化方法只能由invokespecial指令在Java虚拟机内调用,并且只能在未初始化的类实例上调用。实例初始化方法具有从其获得构造函数的访问权限(第2.7.4节)。

一个类或接口最多具有一个类或接口初始化方法,并通过调用该方法进行初始化(第2.17.4节)。类或接口的初始化方法是静态的,不带参数。它有特殊的名字<clinit>。该名称由编译器提供。因为该名称<clinit>不是有效的标识符,所以不能直接用Java编程语言编写的程序中使用它。类和接口初始化方法由Java虚拟机隐式调用。它们从不从任何Java虚拟机指令直接调用,而仅在类初始化过程中间接调用。

Answers:


141

<init> 是实例的构造函数(或构造函数之一),并且是非静态字段初始化。

<clinit> 是该类的静态初始化块,以及静态字段初始化。

class X {

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

   private int x = 1;   // <init>

   X(){
      // <init>
   }

   static {
      // <clinit>
   }

}


14
我的猜测是“阶级”。
Thilo

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,并且在对forName返回的对象使用newInstance时,它将为实例初始化调用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();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.