Inicialización del proceso de carga de clases (10)

inicialización

La inicialización de una clase es el último paso de la carga de la clase, en la fase de preparación, las variables de la clase son todos los valores iniciales especificados por el sistema, y ​​se realizarán según el programa en la fase de inicialización.
Expresión más directa: la fase de inicialización es ejecutar el proceso del método constructor de clases <clinit> () .

La generación del método <clinit> ():
es generado por el compilador recolectando automáticamente la acción de asignación de todas las variables de clase en la clase y la declaración en el bloque de instrucciones estáticas (bloque {} estático). El orden de recopilación del compilador está determinado por el orden en el que aparecen las sentencias en el archivo fuente. El bloque de sentencias estáticas solo puede acceder a las variables definidas antes del bloque de sentencias estáticas, y las variables definidas después de este pueden asignarse al bloque de sentencias estáticas anterior. Pero no se puede acceder a él.

public class Test{
    
    
	static{
    
    
		i = 0; //变量赋值可以正常编译通过
		System.out.print(i);//编译器会提示 “非法向前引用”
	}
	static int i = 1;// 定义在静态语句快之后的变量
}

El método <clinit> () es diferente del método de construcción de clases (<init> ()). No necesita llamar explícitamente al constructor de la clase padre. La máquina virtual Java asegura que el Se ha ejecutado <clinit> () de la clase. Por lo tanto, el tipo del primer método <clinit> () ejecutado en la máquina virtual Java debe ser java.lang.Object.

Dado que el método <clinit> () de la clase principal se ejecuta primero, el bloque de instrucciones estáticas definido en la clase principal es mejor que la operación de asignación de variables de la clase secundaria.
P.ej:

  static class Parent{
    
    
  public static int A = 1;
  static{
    
    
  		A = 2;
	}
}

static class Sub extends Parent{
    
    
	public static int B = A;
}

public static void main(String[] args){
    
    
	System.out.print(Sub.B);
}

输出的为2不为1
  • El método <clinit> () no es necesario para clases e interfaces. Si una clase no tiene un bloque de instrucciones estático y ninguna operación de asignación de variables, entonces el compilador no necesita generar un método <clinit> () para esta clase.
  • Los bloques de código estático no se pueden usar en la interfaz, y todavía hay operaciones de asignación de variables. El método de ejecución de la interfaz <clinit> () no necesita ejecutar primero el método <clinit> () de la interfaz principal, porque solo cuando se utilizan las variables definidas por la interfaz principal Para la inicialización de la interfaz principal, la clase de implementación de la interfaz no ejecutará el método <clinit> () de la interfaz cuando se inicialice.
  • La máquina virtual Java debe garantizar que un método de clase <clinit> () esté correctamente bloqueado y sincronizado en un entorno multiproceso. Si varios subprocesos inicializan una clase, otros subprocesos entrarán en la cola de bloqueo, lo que puede provocar el bloqueo del proceso.
    Nota: Aunque se bloquearán otros subprocesos, si el subproceso que ejecuta el método <clinit> () sale de este método, otros subprocesos no ingresarán al método después de despertar. Bajo el mismo cargador de clases, solo un tipo Se inicializará una vez.

Supongo que te gusta

Origin blog.csdn.net/weixin_43663421/article/details/109299696
Recomendado
Clasificación