Java: ¿Cuál es la diferencia entre <init> y <clinit>?


94

No puedo entender el siguiente texto ... ¿Significa que <clinit>es para constructores vacíos? ¿Por qué es importante tener dos versiones diferentes?

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

2.9. Special Methods

En el nivel de la máquina virtual Java, cada constructor (§2.12) aparece como un método de inicialización de instancia que tiene un nombre especial <init>. Este nombre lo proporciona un compilador. Porque el nombre<init> no es un identificador válido, no se puede utilizar directamente en un programa escrito en el lenguaje de programación Java. Los métodos de inicialización de instancias pueden invocarse solo dentro de la máquina virtual Java mediante la instrucción inokespecial, y pueden invocarse solo en instancias de clases no inicializadas. Un método de inicialización de instancia adquiere los permisos de acceso (§2.7.4) del constructor del que se deriva.

Una clase o interfaz tiene como máximo una clase o método de inicialización de interfaz y se inicializa (§2.17.4) invocando ese método. El método de inicialización de una clase o interfaz es estático y no toma argumentos. Tiene el nombre especial <clinit>. Este nombre lo proporciona un compilador. Dado que el nombre <clinit>no es un identificador válido, no se puede utilizar directamente en un programa escrito en el lenguaje de programación Java. Los métodos de inicialización de clases e interfaces son invocados implícitamente por la máquina virtual Java; nunca se invocan directamente desde ninguna máquina virtual Java en la construcción, sino que sólo se invocan indirectamente como parte del proceso de inicialización de la clase.

Respuestas:


143

<init> es el (o uno de los) constructores de la instancia y la inicialización del campo no estático.

<clinit> son los bloques de inicialización estática para la clase y la inicialización del campo estático.

class X {

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

   private int x = 1;   // <init>

   X(){
      // <init>
   }

   static {
      // <clinit>
   }

}


14
Mi conjetura es "clase".
Thilo

2
@Thilo eso es interesante porque la JVM trata una definición de clase como otro tipo de objeto más.
Jonathan Neufeld

@JonathanNeufeld cierto, aunque creo que hay algunas reglas especiales. Este método (llamado por el inicializador de clase) está marcado como nativo ... grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
Cade Daniel

@Thilo también podría significar "ClassLoader".
Duncan Calvert


13

La diferencia entre <init>y <clinit>es que <init>se usa para métodos constructores que inicializan una instancia de objeto, mientras que <clinit>se usa para inicializar el objeto de clase en sí. Por ejemplo, la inicialización de cualquier staticcampo de nivel de clase se realiza <clinit>cuando la clase se carga e inicia.


1

Solo para agregar Si usa el método Class.forName, solo inicializa la clase. Entonces, desde dentro de este método, realiza una llamada solo a clinit y cuando usa newInstance en el objeto devuelto por forName, llamará a init para la inicialización de la instancia. Puede usar el siguiente código para verlo en depuración.

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

Para probar, use

   Class<ByteCodeParent> bcp2 =(Class<ByteCodeParent>) Class.forName("ByteCodeParent");
ByteCodeParent bcp4= bcp2.newInstance();
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.