usar - Bloque estático en Java no ejecutado
public static java (5)
class Test{
public static void main(String arg[]){
System.out.println("**MAIN METHOD");
System.out.println(Mno.VAL);//SOP(9090);
System.out.println(Mno.VAL+100);//SOP(9190);
}
}
class Mno{
final static int VAL=9090;
static{
System.out.println("**STATIC BLOCK OF Mno/t:"+VAL);
}
}
Sé que un bloque static
se ejecutó cuando se cargó la clase. Pero en este caso la variable de instancia dentro de la clase Mno
es final
, debido a que el bloque static
no se está ejecutando.
¿Por qué es así? Y si eliminara la final
, ¿funcionaría bien?
¿Qué memoria se asignará primero, la variable static final
o el bloque static
?
Si debido al modificador de acceso final
la clase no se carga, ¿cómo puede la variable obtener memoria?
- Un campo
static final int
es una constante en tiempo de compilación y su valor está codificado en la clase de destino sin una referencia a su origen; - por lo tanto, su clase principal no activa la carga de la clase que contiene el campo;
- por lo tanto, el inicializador estático en esa clase no se ejecuta.
En detalle específico, el bytecode compilado corresponde a esto:
public static void main(String arg[]){
System.out.println("**MAIN METHOD");
System.out.println(9090)
System.out.println(9190)
}
Tan pronto como elimine el final
, ya no es una constante en tiempo de compilación y el comportamiento especial descrito anteriormente no se aplica. La clase Mno
se carga como espera y se ejecuta su inicializador estático.
1) Realmente no has extendido esa clase Mno así que cuando comience la compilación generará la constante de la variable VAL y cuando la ejecución comience cuando esa variable es necesaria su carga es de la memoria. No es necesaria la referencia de tu clase para que no se ejecute bock estático .
2) si la clase A amplía esa clase Mno en ese momento ese bloque estático se incluye en la clase A, si lo hace, entonces se ejecutará ese bloque estático. por ejemplo .. public class A extends Mno {
public static void main(String arg[]){
System.out.println("**MAIN METHOD");
System.out.println(Mno.VAL);//SOP(9090);
System.out.println(Mno.VAL+100);//SOP(9190);
}
}
class Mno{
final static int VAL=9090;
static`{`
System.out.println("**STATIC BLOCK OF Mno/t:"+VAL);
}
}
Hasta donde yo sé, se ejecutará en orden de aparición. Por ejemplo :
public class Statique {
public static final String value1 = init1();
static {
System.out.println("trace middle");
}
public static final String value2 = init2();
public static String init1() {
System.out.println("trace init1");
return "1";
}
public static String init2() {
System.out.println("trace init2");
return "2";
}
}
imprimirá
trace init1
trace middle
trace init2
Acabo de probarlo y la estática se inicializa (=> imprimir) cuando la clase "Statique" se usa y se "ejecuta" en otro fragmento de código (en mi caso hice "nueva Statique ()".
La razón por la cual la clase no está cargada es que VAL
es final
Y se inicializa con una expresión constante (9090). Si, y solo si, se cumplen esas dos condiciones, la constante se evalúa en tiempo de compilación y "codificada" cuando es necesario.
Para evitar que la expresión se evalúe en tiempo de compilación (y para que la JVM cargue su clase), puede:
eliminar la palabra clave final:
static int VAL = 9090; //not a constant variable any more
o cambie la expresión del lado derecho a algo no constante (incluso si la variable sigue siendo definitiva):
final static int VAL = getInt(); //not a constant expression any more static int getInt() { return 9090; }
Si ve el bytecode generado usando javap -v Test.class
, main () sale como javap -v Test.class
:
public static void main(java.lang.String[]) throws java.lang.Exception;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String **MAIN METHOD
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: sipush 9090
14: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
17: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
20: sipush 9190
23: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
26: return
Puede ver claramente en " 11: sipush 9090
" que el valor final estático se usa directamente, porque Mno.VAL es una constante de tiempo de compilación. Por lo tanto, no es necesario cargar la clase Mno. Por lo tanto, el bloqueo estático de Mno no se ejecuta.
Puede ejecutar el bloque estático manualmente cargando Mno de la siguiente manera:
class Test{
public static void main(String arg[]) throws Exception {
System.out.println("**MAIN METHOD");
Class.forName("Mno"); // Load Mno
System.out.println(Mno.VAL);
System.out.println(Mno.VAL+100);
}
}
class Mno{
final static int VAL=9090;
static{
System.out.println("**STATIC BLOCK OF Mno/t:"+VAL);
}
}