¿Cuál es la diferencia entre un bloque de código de inicialización estático y no estático?
Mi pregunta es sobre un uso particular de la palabra clave estática. Es posible utilizar static
una palabra clave para cubrir un bloque de código dentro de una clase que no pertenece a ninguna función. Por ejemplo, se compila el siguiente código:
public class Test {
private static final int a;
static {
a = 5;
doSomething(a);
}
private static int doSomething(int x) {
return (x+5);
}
}
Si elimina la static
palabra clave, se queja porque la variable a
es final
. Sin embargo, es posible eliminar las palabras clave final
y static
y compilarlas.
Es confuso para mí en ambos sentidos. ¿Cómo se supone que voy a tener una sección de código que no pertenece a ningún método? ¿Cómo es posible invocarlo? En general, ¿cuál es el propósito de este uso? O mejor, ¿dónde puedo encontrar documentación sobre esto?
El bloque de código con el modificador estático significa un inicializador de clase ; sin el modificador estático, el bloque de código es un inicializador de instancia .
Los inicializadores de clase se ejecutan en el orden en que se definen (de arriba hacia abajo, al igual que los inicializadores de variables simples) cuando se carga la clase (en realidad, cuando se resuelve, pero eso es un tecnicismo).
Los inicializadores de instancia se ejecutan en el orden definido cuando se crea una instancia de la clase, inmediatamente antes de que se ejecute el código del constructor, inmediatamente después de la invocación del superconstructor.
Si lo elimina static
, int a
se convierte en una variable de instancia, a la que no puede acceder desde el bloque inicializador estático. Esto no se podrá compilar y aparecerá el error "No se puede hacer referencia a una variable no estática desde un contexto estático".
Si también lo elimina static
del bloque inicializador, se convierte en un inicializador de instancia y, por lo tanto, int a
se inicializa en la construcción.
¡Uf! ¿Qué es el inicializador estático?
El inicializador estático es un static {}
bloque de código dentro de la clase Java y se ejecuta solo una vez antes de llamar al constructor o al método principal.
¡DE ACUERDO! Dime más...
- es un bloque de código
static { ... }
dentro de cualquier clase java. y ejecutado por una máquina virtual cuando se llama a la clase. - No
return
se admiten declaraciones. - No se apoyan argumentos.
- No
this
osuper
son compatibles.
Mmmm donde puedo usarlo?
Se puede usar en cualquier lugar donde te sientas bien :) así de simple. Pero veo que la mayor parte del tiempo se usa al realizar conexiones de bases de datos, inicio de API, registros, etc.
¡No te limites a ladrar! ¿Dónde está el ejemplo?
package com.example.learnjava;
import java.util.ArrayList;
public class Fruit {
static {
System.out.println("Inside Static Initializer.");
// fruits array
ArrayList<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Orange");
fruits.add("Pear");
// print fruits
for (String fruit : fruits) {
System.out.println(fruit);
}
System.out.println("End Static Initializer.\n");
}
public static void main(String[] args) {
System.out.println("Inside Main Method.");
}
}
¿¿¿Producción???
Inicializador estático interior.
Manzana
Naranja
Pera
Finalizar el inicializador estático.
Dentro del método principal.
El static
bloque es un "inicializador estático".
Se invoca automáticamente cuando se carga la clase y no hay otra forma de invocarla (ni siquiera a través de Reflection).
Personalmente, solo lo he usado al escribir código JNI:
class JNIGlue {
static {
System.loadLibrary("foo");
}
}
Esto es directamente de http://www.programcreek.com/2011/10/java-class-instance-initializers/
1. Orden de Ejecución
Mira la siguiente clase, ¿sabes cuál se ejecuta primero?
public class Foo {
//instance variable initializer
String s = "abc";
//constructor
public Foo() {
System.out.println("constructor called");
}
//static initializer
static {
System.out.println("static initializer called");
}
//instance initializer
{
System.out.println("instance initializer called");
}
public static void main(String[] args) {
new Foo();
new Foo();
}
}
Producción:
inicializador estático llamado
inicializador de instancia llamado
constructor llamado
inicializador de instancia llamado
constructor llamado
2. ¿Cómo funciona el inicializador de instancias de Java?
El inicializador de instancia anterior contiene una declaración println. Para entender cómo funciona, podemos tratarlo como una declaración de asignación de variables, por ejemplo, b = 0
. Esto puede hacer que sea más obvio de entender.
En lugar de
int b = 0
, podrías escribir
int b;
b = 0;
Por lo tanto, los inicializadores de instancia y los inicializadores de variables de instancia son prácticamente iguales.
3. ¿Cuándo son útiles los inicializadores de instancias?
El uso de inicializadores de instancia es poco común, pero aún así puede ser una alternativa útil a los inicializadores de variables de instancia si:
- El código inicializador debe manejar excepciones.
- Realice cálculos que no se pueden expresar con un inicializador de variable de instancia.
Por supuesto, dicho código podría escribirse en constructores. Pero si una clase tuviera varios constructores, tendrías que repetir el código en cada constructor.
Con un inicializador de instancia, puede escribir el código una vez y se ejecutará sin importar qué constructor se utilice para crear el objeto. (Supongo que esto es sólo un concepto y no se usa con frecuencia).
Otro caso en el que los inicializadores de instancia son útiles son las clases internas anónimas, que no pueden declarar ningún constructor. (¿Será este un buen lugar para colocar una función de registro?)
Gracias a Derhein.
También tenga en cuenta que las clases anónimas que implementan interfaces [1] no tienen constructores. Por lo tanto, se necesitan inicializadores de instancia para ejecutar cualquier tipo de expresión en el momento de la construcción.
"final" garantiza que una variable debe inicializarse antes del final del código inicializador del objeto. Del mismo modo, "final estático" garantiza que una variable se inicializará al final del código de inicialización de clase. Omitir lo "estático" de su código de inicialización lo convierte en código de inicialización de objeto; por tanto su variable ya no satisface sus garantías.