java - usar - ¿Por qué.class no invoca el bloque estático en una Clase?
public static java (2)
Este es el código que tengo:
public class StupidClass {
static {
System.out.println("Stupid class loaded!");
}
}
Y las pruebas que tengo, que ejecuto por separado .
import org.junit.Test;
public class StupidTest {
@Test
public void foo() throws ClassNotFoundException {
final Class<?> stupidClass = Class.forName("StupidClass");
System.out.println(stupidClass.getSimpleName());
}
@Test
public void bar() throws ClassNotFoundException {
final Class<StupidClass> stupidClassClass = StupidClass.class;
System.out.println(stupidClassClass.getSimpleName());
}
}
Cuando ejecuto test foo veré:
Stupid class loaded!
StupidClass
Pero cuando ejecuto la barra de prueba , todo lo que veo es:
StupidClass
Citando de this página ...
La máquina virtual Java crea automáticamente los objetos de clase a medida que las clases se cargan y mediante llamadas al método defineClass en el cargador de clases.
Entonces, entiendo que, en la barra de prueba, se carga la clase Estúpido, de lo contrario, ¿habría visto un valor nulo, supongo? Entonces, el objeto Class se crea porque la clase misma se carga.
Y ahora citando desde this página
Los bloques de inicialización estática se ejecutan cuando el JVM (cargador de clases, para ser específico) carga StaticClass (que ocurre la primera vez que se hace referencia en el código).
Así que espero ver la "¡Estúpida clase cargada!" texto en la barra de prueba también, pero no lo soy.
También citando de Thinking in Java
Cada una de las clases Candy, Gum y Cookie tiene una cláusula estática que se ejecuta cuando la clase se carga por primera vez.
lo cual no es muy exacto parece ...
¿Qué me estoy perdiendo?
Los bloques de inicialización estática se ejecutan cuando el JVM (cargador de clases, para ser específico) carga StaticClass (que ocurre la primera vez que se hace referencia en el código).
La cita anterior es simplemente errónea, pero es solo una instancia de una idea errónea muy extendida.
-
La clase no se inicializa cuando se está cargando, sino cuando se hace referencia por primera vez a un miembro de clase estático. Esto se rige precisamente por la specification .
-
La carga de la clase no ocurre cuando se hace referencia a la clase por primera vez, sino en un punto dependiente de la implementación.
-
El último momento en que se debe cargar la clase es cuando se hace referencia a la clase, que no es lo mismo que hacer referencia a un miembro de la clase.
Class.forName
inicializa la clase de forma predeterminada, pero tiene la opción de llamar a una sobrecarga que toma una
boolean initialize
y proporciona
false
.
Obtendrá la clase cargada sin inicializar.
La carga de clases y la inicialización son 2 cosas diferentes. Una clase puede cargarse pero no inicializarse hasta que sea realmente necesaria. Los inicializadores estáticos se ejecutan solo cuando una clase se está inicializando <> NO cargada, "inicializada"
En el primer caso, está cargando e inicializando una clase cuando usa
class.forName()
, por eso se ejecutan los inicializadores estáticos y, por lo tanto, ve
"Stupid class loaded!"
como salida
En el segundo caso, solo está asignando una referencia de la clase,
la clase está cargada
(use java -verbose: class para ver qué clases están cargadas) pero en realidad no la está inicializando (o para ser más precisos, no haciendo cualquier cosa que obligue a los inicializadores a ejecutarse).
¡Por lo tanto, no verá la salida como una
Stupid class loaded!
.
Intente hacer algo como llamar a
newInstance()
en la clase, debería forzar la inicialización de la clase y debería ver la
Stupid class loaded!
Mi código :
public class CheckPalindrome {
public static void main(String[] args) {
Class<Test> t = Test.class;
}
}
// class being loaded
class Test {
static {
System.out.println("aaa");
}
}
Clases que están cargadas
...
[Loaded Test from file:/Workspaces/SampleTest/Java8/bin/]
...
^ - Esto muestra que la clase se carga pero no se inicializa.