Java: qual è la differenza tra <init> e <clinit>?


94

Non riesco a capire il testo seguente ... Significa che <clinit>è per costruttori vuoti? Perché è importante avere due versioni differenti?

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

2.9. Special Methods

A livello della Java virtual machine, ogni costruttore (§2.12) appare come un metodo di inizializzazione dell'istanza che ha il nome speciale <init>. Questo nome viene fornito da un compilatore. Poiché il nome <init>non è un identificativo valido, non può essere utilizzato direttamente in un programma scritto nel linguaggio di programmazione Java. I metodi di inizializzazione delle istanze possono essere richiamati solo all'interno della Java virtual machine dall'istruzione invokespecial e possono essere richiamati solo su istanze di classe non inizializzate. Un metodo di inizializzazione dell'istanza assume i permessi di accesso (§2.7.4) del costruttore da cui è stato derivato.

Una classe o interfaccia ha al massimo una classe o un metodo di inizializzazione dell'interfaccia e viene inizializzata (§2.17.4) invocando quel metodo. Il metodo di inizializzazione di una classe o di un'interfaccia è statico e non accetta argomenti. Ha il nome speciale <clinit>. Questo nome viene fornito da un compilatore. Poiché il nome <clinit>non è un identificativo valido, non può essere utilizzato direttamente in un programma scritto nel linguaggio di programmazione Java. I metodi di inizializzazione della classe e dell'interfaccia vengono richiamati implicitamente dalla Java virtual machine; non vengono mai richiamati direttamente da alcuna macchina virtuale Java in w2struction, ma vengono richiamati solo indirettamente come parte del processo di inizializzazione della classe.

Risposte:


143

<init> è il (o uno dei) costruttori per l'istanza e l'inizializzazione del campo non statico.

<clinit> sono i blocchi di inizializzazione statici per la classe e l'inizializzazione del campo statico.

class X {

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

   private int x = 1;   // <init>

   X(){
      // <init>
   }

   static {
      // <clinit>
   }

}


14
La mia ipotesi è "classe".
Thilo

2
@Thilo è interessante perché la JVM tratta una definizione di classe solo come un altro tipo di oggetto.
Jonathan Neufeld,

@JonathanNeufeld vero, anche se penso che ci siano alcune regole speciali. Questo metodo (chiamato dall'inizializzatore
Cade Daniel

@Thilo potrebbe anche significare "ClassLoader".
Duncan Calvert


13

La differenza tra <init>e <clinit>è che <init>viene utilizzata per i metodi del costruttore che inizializzano un'istanza di un oggetto, mentre <clinit>viene utilizzata per inizializzare l'oggetto della classe stesso. Ad esempio, l'inizializzazione di qualsiasi staticcampo a livello di classe viene eseguita <clinit>quando la classe viene caricata e inizializzata.


1

Solo per aggiungere Se usi il metodo Class.forName, inizializza solo la classe. Quindi dall'interno di questo metodo, effettua una chiamata solo a clinit e quando usi newInstance sull'oggetto restituito da forName, chiamerà init per l'inizializzazione dell'istanza. Puoi usare il codice sottostante per vederlo nel debug.

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

Per testare, utilizzare

   Class<ByteCodeParent> bcp2 =(Class<ByteCodeParent>) Class.forName("ByteCodeParent");
ByteCodeParent bcp4= bcp2.newInstance();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.