usar - utilidad de static en los programas en java
El valor de la variable estática no cambió incluso después de inicializar la clase secundaria en Java (8)
Esta pregunta ya tiene una respuesta aquí:
- Ejecución de bloques estáticos de Java en subclases 2 respuestas.
Cuando invoco la variable estática y
utilizando Checks.y
(los Checks
son una subclase), el bloque estático no se ejecuta y el valor de y
no se actualiza.
class Par {
static int y = 4;
}
class Checks extends Par {
static {
y = 5;
}
}
public class Check {
public static void main(String args[]) {
System.out.println(Checks.y); // here printing 4
}
}
Como la estática se comparte entre todas las subclases, se supone que el valor se actualiza.
¿Cuál podría ser la razón detrás de esto?
Aquí hay una variante de cómo forzar la inicialización de la clase Checks
.
class Par {
static int y = 4;
}
class Checks extends Par {
public static int x;
static {
y = 5;
}
}
class Check {
public static void main(String args[]) {
System.out.println(checks.y); // Prints 4
System.out.println(checks.x); // Prints 0
System.out.println(checks.y); // Prints 5
}
}
Aquí:
System.out.println(checks.y); // Here printing 4
y
refiere a un campo de la clase par
. Este campo accede a los resultados en la carga de la clase par
(la clase padre) de acuerdo con el JLS (el énfasis es mío):
12.4. Inicialización de Clases e Interfaces
....
12.4.1. Cuando ocurre la inicialización
Una clase o tipo de interfaz T se inicializará inmediatamente antes de la primera aparición de cualquiera de los siguientes: T es una clase y se crea una instancia de T. Se invoca un método estático declarado por T
Se asigna un campo estático declarado por T
Se usa un campo estático declarado por T y el campo no es una variable constante (§4.12.4).
T es una clase de nivel superior (§7.6) y se ejecuta una declaración de afirmación (§14.10) anidada léxicamente dentro de T (§8.1.3).
Pero no carga la clase de checks
porque (el énfasis es mío):
Una referencia a un campo estático (§8.3.1.1) provoca la inicialización de solo la clase o interfaz que realmente lo declara , incluso aunque se pueda hacer referencia a él a través del nombre de una subclase, una subinterfaz o una clase que implementa una interfaz.
Como otros lo mencionan, el bloque estático no se ejecuta porque la clase no se inicializó como se respondió antes .
Observe que los nombres de las convenciones de clase comienzan con una letra mayúscula.
Un ejemplo más claro para mostrar que no se usa la clase Anulada:
class Par {
static int y = 4;
public static void main(String args[]) {
System.out.println(Checks.y); // Here printing 4
System.out.println(new Checks().y); // Here printing 5
}
}
class Checks extends Par {
static {
y = 5;
}
}
Desde JLS 12.4.1 :
Una clase o tipo de interfaz T se inicializará inmediatamente antes de la primera aparición de cualquiera de los siguientes:
- T es una clase y se crea una instancia de T
- T es una clase y se invoca un método estático declarado por T
- Se asigna un campo estático declarado por T
- Se usa un campo estático declarado por T y el campo no es una variable constante (§4.12.4).
- T es una clase de nivel superior (§7.6), y se ejecuta una declaración de afirmación (§14.10) anidada léxicamente dentro de T (§8.1.3).
Como y no se declara en los cheques, ninguno de los criterios anteriores se cumple.
Otra forma de ilustrar este comportamiento:
class par {
static int y = 4;
static {
System.out.println("static constructor of par");
}
}
class checks extends par {
static int x = 6;
static {
System.out.println("checks static constructor");
y = 5;
}
}
public class check{
public static void main(String args[]){
System.out.println(checks.y);
System.out.println(checks.x);
System.out.println(checks.y);
}
}
Salida
static constructor of par
4
checks static constructor
6
5
Entonces, después de invocar checks.x
que satisface la segunda regla, se invoca al constructor estático.
El único aspecto no mencionado hasta ahora que podría ser confuso para los nuevos programadores de Java: ¡el hecho de cómo organizar su código fuente no importa hasta cierto punto!
Tiene sus dos clases (que deberían ser nombradas entre Parent y Child por cierto para seguir las convenciones de nomenclatura de Java) en un archivo, o en un ejemplo. Así que probablemente asumas: estas cosas se juntan automáticamente en el tiempo de ejecución.
Pero en tiempo de ejecución, hay archivos de clase individuales por clase. Y como han dicho los demás: nada en el código hace referencia a la clase infantil. ¡Así que esa clase no está cargada, entonces la tarea no ocurre!
El campo y
no es declarado por la clase Checks
.
La lectura de campos estáticos no desencadena la inicialización de la clase a la que se hace referencia ( Checks
), a menos que esa clase sea aquella en la que se declara el campo (consulte la cita de JLS a continuación). En este ejemplo, incluso si se accede a y
a través de Checks
, eso solo activará la inicialización de Par
porque Par
es la clase que declara y
.
En otras palabras, los Checks
clase en un sentido no se utilizan en tiempo de ejecución.
Esta es quizás una ilustración de por qué es incorrecto acceder a miembros static
través de subclases, algo que provoca una advertencia en tiempo de compilación.
Hay una explicación simple en la especificación :
12.4.1. Cuando ocurre la inicialización
Una clase o tipo de interfaz T se inicializará inmediatamente antes de la primera aparición de cualquiera de los siguientes:
T es una clase y se crea una instancia de T
Se invoca un método estático declarado por T
Se asigna un campo estático declarado por T
Se usa un campo estático declarado por T y el campo no es una variable constante (§4.12.4).
T es una clase de nivel superior (§7.6) y se ejecuta una declaración de afirmación (§14.10) anidada léxicamente dentro de T (§8.1.3).
...
Una referencia a un campo estático (§8.3.1.1) provoca la inicialización de solo la clase o interfaz que realmente lo declara, incluso aunque se pueda hacer referencia a él a través del nombre de una subclase, una subinterfaz o una clase que implementa una interfaz.
La última nota explica por qué su subclase no se está inicializando.
Esto se debe a que el bloque static
en la clase de checks
no se ejecuta. Aunque mencione que la clase checks
la JVM no la carga en absoluto.
Puede confirmar esto agregando otro System.out.println
dentro del bloque estático.
class checks extends par {
static {
System.out.println("Test");
y = 5;
}
}
La palabra Test
nunca se imprimirá.
Lea la sección 12.4.1. Cuando se produce la inicialización de la especificación del lenguaje Java para saber más.
Según su ejemplo, el bloque estático de la clase Check nunca se llama. Los bloques estáticos siempre se ejecutan antes de crear el objeto. Si agrega cheques, object = new checks()
, en su clase de Cheque debería ver el valor esperado.