Java: Qual é a diferença entre <init> e <clinit>?


93

Não consigo entender o seguinte texto ... Isso significa que <clinit>é para construtores vazios? Por que é importante ter duas versões diferentes?

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

2.9. Special Methods

No nível da máquina virtual Java, cada construtor (§2.12) aparece como um método de inicialização de instância que possui o nome especial <init>. Este nome é fornecido por um compilador. Como o nome <init>não é um identificador válido, ele não pode ser usado diretamente em um programa escrito na linguagem de programação Java. Os métodos de inicialização de instância podem ser chamados apenas na máquina virtual Java pela instrução invokespecial e podem ser chamados apenas em instâncias de classe não inicializadas. Um método de inicialização de instância assume as permissões de acesso (§2.7.4) do construtor do qual foi derivado.

Uma classe ou interface tem no máximo um método de inicialização de classe ou interface e é inicializada (§2.17.4) invocando esse método. O método de inicialização de uma classe ou interface é estático e não leva argumentos. Tem um nome especial <clinit>. Este nome é fornecido por um compilador. Como o nome <clinit>não é um identificador válido, ele não pode ser usado diretamente em um programa escrito na linguagem de programação Java. Os métodos de inicialização de classe e interface são chamados implicitamente pela máquina virtual Java; eles nunca são chamados diretamente de qualquer instrução de máquina virtual Java, mas são chamados apenas indiretamente como parte do processo de inicialização da classe.

Respostas:


141

<init> é o (ou um dos) construtor (es) da instância e inicialização de campo não estático.

<clinit> são os blocos de inicialização estáticos para a classe e a inicialização de campo estático.

class X {

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

   private int x = 1;   // <init>

   X(){
      // <init>
   }

   static {
      // <clinit>
   }

}


14
Meu palpite é "classe".
Thilo

2
@Thilo isso é interessante porque a JVM trata uma definição de classe como apenas outro tipo de objeto também.
Jonathan Neufeld

@JonathanNeufeld true, embora eu ache que existem algumas regras especiais. Este método (chamado pelo inicializador de classe) é marcado como nativo ... grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
Cade Daniel

@Thilo também pode significar "ClassLoader".
Duncan Calvert


13

A diferença entre <init>e <clinit>é que <init>é usado para métodos construtores que inicializam uma instância de objeto, enquanto <clinit>é usado para inicializar o próprio objeto de classe. Por exemplo, a inicialização de quaisquer staticcampos de nível de classe é feita <clinit>quando a classe é carregada e inicializada.


1

Apenas para adicionar Se você usar o método Class.forName, ele apenas inicializa a classe. Portanto, a partir desse método, ele faz uma chamada apenas para clinit e quando você usa newInstance no objeto retornado de forName, ele chama init para a inicialização da instância. Você pode usar o código abaixo para vê-lo na depuração.

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 testar, use

   Class<ByteCodeParent> bcp2 =(Class<ByteCodeParent>) Class.forName("ByteCodeParent");
ByteCodeParent bcp4= bcp2.newInstance();
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.