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 static
bloque se ejecuta cuando se carga la clase. Pero en este caso, la variable de instancia dentro de la clase Mno
es final
, debido a que el static
bloque no se está ejecutando.
¿Por qué es así? Y si quito el final
, ¿funcionaría bien?
¿Qué memoria se asignará primero, la static final
variable o el static
bloque?
Si debido al final
modificador de acceso la clase no se carga, ¿cómo puede la variable obtener memoria?
java
static
access-modifiers
Sthita
fuente
fuente
Respuestas:
static final int
campo es una constante en tiempo de compilación y su valor está codificado en la clase de destino sin una referencia a su origen;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 lo elimine
final
, ya no será una constante en tiempo de compilación y el comportamiento especial descrito anteriormente no se aplicará. LaMno
clase se carga como espera y se ejecuta su inicializador estático.fuente
La razón por la clase no se carga es que
VAL
esfinal
Y es inicializado 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 se "codifica" cuando sea 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 aún es final):
final static int VAL = getInt(); //not a constant expression any more static int getInt() { return 9090; }
fuente
Si ve el código de bytes generado usando
javap -v Test.class
, main () sale como: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 tanto, el bloque estático de Mno no se ejecuta.Puede ejecutar el bloque estático cargando manualmente Mno como se muestra a continuación:
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); } }
fuente
En realidad, no ha extendido esa clase Mno, por lo que cuando la compilación comience, generará una constante de variable VAL y cuando la ejecución comience, cuando esa variable sea necesaria, su carga será desde la memoria. Por lo tanto, no es necesario que su clase haga referencia para que no se ejecute el bock estático.
si la clase
A
extiende la claseMno
, el bloque estático se incluye en la clase;A
si hace esto, se ejecuta 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); } }
fuente
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á
Lo acabo de probar y las estáticas se inicializan (=> imprimir) cuando la clase "Statique" se usa y se "ejecuta" en otra parte del código (en mi caso hice "new Statique ()".
fuente
Statique
clase haciendonew Statique()
. Mientras que en la pregunta formulada, laMno
clase no se carga en absoluto.