¿Cuál es la diferencia entre un bloque de código de inicialización estático y uno no estático?

8 minutos de lectura

¿Cuál es la diferencia entre un bloque de código de inicialización estático y uno no estático?
Szère Dyeri

Mi pregunta es sobre un uso particular de la palabra clave estática. Es posible usar static palabra clave para cubrir un bloque de código dentro de una clase que no pertenece a ninguna función. Por ejemplo, el siguiente código compila:

public class Test {
    private static final int a;    
    static {
        a = 5;
        doSomething(a);
    }
    private static int doSomething(int x) {
        return (x+5);
    }
}

Si quitas el static palabra clave se queja porque la variable a es final. Sin embargo, es posible eliminar ambos final y static palabras clave y hacerlo compilar.

Es confuso para mí en ambos sentidos. ¿Cómo se supone que debo 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?

¿Cuál es la diferencia entre un bloque de código de inicialización estático y uno no estático?
lorenzo dol

El bloque de código con el modificador estático significa un clase inicializador; sin el modificador estático, el bloque de código es un ejemplo inicializador.

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 instancias se ejecutan en el orden definido cuando se instancia la clase, inmediatamente antes de que se ejecute el código del constructor, inmediatamente después de la invocación del superconstructor.

si quitas static desde int a, se convierte en una variable de instancia, a la que no puede acceder desde el bloque inicializador estático. Esto fallará al compilar con el error “no se puede hacer referencia a la variable no estática a desde un contexto estático”.

si tambien quitas static desde el bloque inicializador, luego se convierte en un inicializador de instancia y así int a se inicializa en la construcción.

  • El inicializador estático en realidad se invoca más tarde, cuando se inicializa la clase, después de que se haya cargado y vinculado. Eso sucede cuando crea una instancia de un objeto de una clase o accede a una variable o método estático en la clase. De hecho, si tiene una clase con un inicializador estático y un método public static void staticMethod(){}si ejecutas TestStatic.class.getMethod("staticMethod");. No se invocará el inicializador estático. Más información aquí docs.oracle.com/javase/specs/jvms/se10/html/…

    – Totó

    11/10/2018 a las 10:50


  • @Totò: Sí, eso es lo que implica la resolución de la clase (al menos solían referirse a ella como link+init como “resolución” hace mucho tiempo). No me sorprende que puedas usar la reflexión para descubrir cosas. sobre una clase sin que se resuelva.

    – Lawrence Dol

    12/10/2018 a las 20:36

¡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 que se llame al constructor o al método principal.

¡OK! Dime más…

  • es un bloque de código static { ... } dentro de cualquier clase java. y ejecutado por la máquina virtual cuando se llama a la clase.
  • No return Las declaraciones son compatibles.
  • No se admiten argumentos.
  • No this o super son compatibles.

Hmm, ¿dónde puedo usarlo?

Se puede usar en cualquier lugar donde te sientas bien 🙂 así de simple. Pero veo que la mayoría de las veces se usa cuando se realiza la conexión a la base de datos, el inicio de la API, el registro, etc.

¡No solo ladres! donde esta 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

Fin del inicializador estático.

Dentro del método principal.

¡Espero que esto ayude!

  • Gracias madan! ¿Se puede usar un bloque estático en lugar de afterPropertiesSet() de InitializingBean?

    – Alejandro Surafel

    2 de junio de 2015 a las 7:52

  • ¡Sí tu puedes! El inicializador estático se llama cuando jvm carga la clase. Así que es realmente la primera fase en la que se ejecuta el código. Si también tiene un constructor, el orden sería: inicializador estático, constructor, afterPropertiesSet

    – Martín Baumgartner

    7 oct 2015 a las 12:49

¿Cuál es la diferencia entre un bloque de código de inicialización estático y uno no estático?
Alnitak

los static block es un “inicializador estático”.

Se invoca automáticamente cuando se carga la clase y no hay otra forma de invocarlo (ni siquiera a través de Reflection).

Personalmente, solo lo he usado al escribir código JNI:

class JNIGlue {
    static {
        System.loadLibrary("foo");
    }
}

  • No, no hay una forma explícita de invocarlo, el inicializador de clase nunca está representado por un Method instancia pero solo invocada por la máquina virtual Java.

    –Rafael Winterhalter

    17 de junio de 2014 a las 15:32

¿Cuál es la diferencia entre un bloque de código de inicialización estático y uno no estático?
alexei fando

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 instrucció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 = 0podrí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 instancias es raro, pero aun así puede ser una alternativa útil a los inicializadores de variables de instancia si:

  1. El código del inicializador debe manejar las excepciones
  2. 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ía que repetir el código en cada constructor.

Con un inicializador de instancias, solo puede escribir el código una vez y se ejecutará sin importar qué constructor se use para crear el objeto. (Supongo que esto es solo 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 tiene constructores. Por lo tanto, se necesitan inicializadores de instancias 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 de inicialización del objeto. Del mismo modo, “static final” garantiza que una variable se inicializará al final del código de inicialización de clase. Omitir el “estático” de su código de inicialización lo convierte en un código de inicialización de objetos; por lo tanto, su variable ya no satisface sus garantías.

¿Cuál es la diferencia entre un bloque de código de inicialización estático y uno no estático?
Vicente Ramdhanie

No escribirá código en un bloque estático que deba invocarse en cualquier parte de su programa. Si el objetivo del código es invocarlo, debe colocarlo en un método.

Puede escribir bloques inicializadores estáticos para inicializar variables estáticas cuando se carga la clase, pero este código puede ser más complejo.

Un bloque inicializador estático parece un método sin nombre, sin argumentos y sin tipo de retorno. Como nunca lo llamas, no necesita un nombre. La única vez que se llama es cuando la máquina virtual carga la clase.

¿Cuál es la diferencia entre un bloque de código de inicialización estático y uno no estático?
cardman

cuando un desarrollador usa un bloque inicializador, el compilador de Java copia el inicializador en cada constructor de la clase actual.

Ejemplo:

el siguiente código:

class MyClass {

    private int myField = 3;
    {
        myField = myField + 2;
        //myField is worth 5 for all instance
    }

    public MyClass() {
        myField = myField * 4;
        //myField is worth 20 for all instance initialized with this construtor
    }

    public MyClass(int _myParam) {
        if (_myParam > 0) {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
            //if _myParam is greater than 0
        } else {
            myField = myField + 5;
            //myField is worth 10 for all instance initialized with this construtor
            //if _myParam is lower than 0 or if _myParam is worth 0
        }
    }

    public void setMyField(int _myField) {
        myField = _myField;
    }


    public int getMyField() {
        return myField;
    }
}

public class MainClass{

    public static void main(String[] args) {
        MyClass myFirstInstance_ = new MyClass();
        System.out.println(myFirstInstance_.getMyField());//20
        MyClass mySecondInstance_ = new MyClass(1);
        System.out.println(mySecondInstance_.getMyField());//20
        MyClass myThirdInstance_ = new MyClass(-1);
        System.out.println(myThirdInstance_.getMyField());//10
    }
}

es equivalente a:

class MyClass {

    private int myField = 3;

    public MyClass() {
        myField = myField + 2;
        myField = myField * 4;
        //myField is worth 20 for all instance initialized with this construtor
    }

    public MyClass(int _myParam) {
        myField = myField + 2;
        if (_myParam > 0) {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
            //if _myParam is greater than 0
        } else {
            myField = myField + 5;
            //myField is worth 10 for all instance initialized with this construtor
            //if _myParam is lower than 0 or if _myParam is worth 0
        }
    }

    public void setMyField(int _myField) {
        myField = _myField;
    }


    public int getMyField() {
        return myField;
    }
}

public class MainClass{

    public static void main(String[] args) {
        MyClass myFirstInstance_ = new MyClass();
        System.out.println(myFirstInstance_.getMyField());//20
        MyClass mySecondInstance_ = new MyClass(1);
        System.out.println(mySecondInstance_.getMyField());//20
        MyClass myThirdInstance_ = new MyClass(-1);
        System.out.println(myThirdInstance_.getMyField());//10
    }
}

Espero que mi ejemplo sea entendido por los desarrolladores.

¿Ha sido útil esta solución?