Java: ¿Cuándo es útil un bloque de inicialización estático?

91

¿Cuál es la diferencia entre la inicialización dentro de un staticbloque?

public class staticTest {

    static String s;
    static int n;
    static double d;

    static {
        s = "I'm static";
        n = 500;
        d = 4000.0001;
    }
    ...

E inicialización estática individual:

public class staticTest {

    static String s = "I'm static";
    static int n    = 500;
    static double d = 4000.0001;

    ....
Adam Matan
fuente
1
Solo está usando asignaciones en el bloque de inicialización estática, por lo que, por supuesto, se pueden hacer usando la asignación de variables estáticas. ¿Ha intentado ver qué sucede si necesita ejecutar declaraciones de no asignación?
Platinum Azure
Es un buen lugar para cargar clases o cargar bibliotecas nativas.
qrtt1
1
Tenga en cuenta que las variables estáticas deben evitarse y, por lo tanto, los bloques de inicialización estáticos generalmente no son una buena idea. Si los usa mucho, espere algunos problemas en el futuro.
Bill K

Respuestas:

106

Un bloque de inicialización estático permite una inicialización más compleja, por ejemplo, utilizando condicionales:

static double a;
static {
    if (SomeCondition) {
      a = 0;
    } else {
      a = 1;
    }
}

O cuando se requiere algo más que construcción: cuando se usa un constructor para crear su instancia, es necesario el manejo de excepciones o el trabajo que no sea la creación de campos estáticos.

Un bloque de inicialización estático también se ejecuta después de los inicializadores estáticos en línea, por lo que lo siguiente es válido:

static double a;
static double b = 1;

static {
    a = b * 4; // Evaluates to 4
}
Rich O'Kelly
fuente
3
Haciendo "b = a * 4;" inline solo sería un problema si b se declarara antes de a, que no es el caso en su ejemplo.
George Hawkins
1
@GeorgeHawkins Solo intentaba ilustrar que un inicializador estático se ejecuta después de inicializadores en línea, no que no se pueda hacer un equivalente en línea. Sin embargo, tomo su punto y he actualizado el ejemplo para (con suerte) ser más claro.
Rich O'Kelly
1
Sólo por diversión, podría señalar que su primer ejemplo podría ser fácilmente "doble estático a = alguna condición? 0: 1;" No es que tus ejemplos no sean geniales, solo digo ... :)
Bill K
18

Un uso típico:

private final static Set<String> SET = new HashSet<String>();

static {
    SET.add("value1");
    SET.add("value2");
    SET.add("value3");
}

¿Cómo lo haría sin un inicializador estático?

gawi
fuente
2
Respuesta: Guayaba :) +1
Paul Bellora
2
Otra respuesta sin bibliotecas adicionales: cree un método estático que encapsule la inicialización SETy use la variable initializer ( private final static Set<String> SET = createValueSet()). ¿Qué pasa si tienes 5 conjuntos y 2 mapas, simplemente los volcarías todos en un solo staticbloque?
TWiStErRob
14

Puede usar el bloque try / catch dentro static{}como se muestra a continuación:

MyCode{

    static Scanner input = new Scanner(System.in);
    static boolean flag = true;
    static int B = input.nextInt();
    static int H = input.nextInt();

    static{
        try{
            if(B <= 0 || H <= 0){
                flag = false;
                throw new Exception("Breadth and height must be positive");
            }
        }catch(Exception e){
            System.out.println(e);
        }

    }
}

PD: ¡Referido de esto !

karan patel
fuente
11

El manejo de excepciones durante la inicialización es otra razón. Por ejemplo:

static URL url;
static {
    try {
        url = new URL("https://blahblah.com");
    }
    catch (MalformedURLException mue) {
        //log exception or handle otherwise
    }
}

Esto es útil para constructores que lanzan de forma molesta excepciones comprobadas, como las anteriores, o una lógica de inicialización más compleja que podría ser propensa a excepciones.

Paul Bellora
fuente
5

A veces, desea hacer más que simplemente asignar valores a variables estáticas. Dado que no puede colocar declaraciones arbitrarias en el cuerpo de la clase, puede usar un bloque inicializador estático.

Jesper
fuente
4

En su ejemplo, no hay diferencia; pero a menudo el valor inicial es más complejo de lo que se expresa cómodamente en una sola expresión (por ejemplo, es un List<String>cuyo contenido se expresa mejor mediante un forbucle; o es un Methodque podría no existir, por lo que se necesitan manejadores de excepciones), y / o los campos estáticos deben configurarse en un orden específico.

ruakh
fuente
4

staticEl bloque se puede usar para inicializar la instancia singleton , para evitar el uso del método sincronizado getInstance() .

Marinero danubiano
fuente
3

Técnicamente, podría salirse con la suya sin él. Algunos prefieren el código de inicialización de varias líneas para utilizar un método estático. Estoy bastante contento de usar un inicializador estático para una inicialización de varias declaraciones relativamente simple.

Por supuesto, casi siempre hago mi estática finaly apunto a un objeto inmodificable.

Tom Hawtin - tackline
fuente
3

La palabra clave estática (ya sea una variable o un bloque) pertenece a la clase. Entonces, cuando se llama a la clase, se ejecutan estas variables o bloques. Entonces, la mayor parte de la inicialización se realizará con la ayuda de una palabra clave estática. Como pertenece a la propia clase, la clase puede acceder directamente a ella, sin crear una instancia de la clase.

Tomemos un ejemplo, hay una clase de calzado en la que hay varias variables como color, talla, marca, etc ... Y aquí si la empresa fabricante de calzado tiene solo una marca, debemos inicializarla como una variable estática. Entonces, cuando se llama a la clase de zapatos y se fabrican diferentes tipos de zapatos (creando una instancia de la clase), en ese momento, el color y el tamaño ocuparán la memoria cada vez que se cree un nuevo zapato, pero aquí la marca es una propiedad común para todos los zapatos, de modo que ocupará la memoria por una vez sin importar cuántos zapatos se fabriquen.

Ejemplo:

    class Shoe {
    int size;
    String colour;
    static String brand = "Nike";

    public Shoe(int size, String colour) {
        super();
        this.size = size;
        this.colour = colour;
    }

    void displayShoe() {
        System.out.printf("%-2d %-8s %s %n",size,colour, brand);
    }

    public static void main(String args[]) {
        Shoe s1 = new Shoe(7, "Blue");
        Shoe s2 = new Shoe(8, "White");

        System.out.println("=================");
        s1.displayShoe();
        s2.displayShoe();
        System.out.println("=================");
    }
}
imbuido
fuente
1

Usamos constructores para inicializar nuestras variables de instancia (variables no estáticas, variables que pertenecen a objetos, no a la clase).

Si desea inicializar variables de clase (variables estáticas) y desea hacerlo sin crear un objeto (los constructores solo se pueden llamar al crear un objeto), entonces necesita bloques estáticos.

static Scanner input = new Scanner(System.in);
static int widht;
static int height;

static
{
    widht = input.nextInt();
    input.nextLine();
    height = input.nextInt();
    input.close();

    if ((widht < 0) || (height < 0))
    {
        System.out.println("java.lang.Exception: Width and height must be positive");
    }
    else
    {
        System.out.println("widht * height = " + widht * height);
    }
}
Miguel
fuente
Leer stdin en un inicializador estático es una idea bastante terrible. Y System.out.println("B * H");es bastante inútil. Y la respuesta en sí es bastante vaga. OP no mencionó constructores ni variables de instancia.
shmosel
Este es solo un ejemplo que muestra qué es un inicializador estático y cómo se usa. OP no solicitó constructores o variables de instancia, pero para enseñarle la diferencia entre el inicializador estático y el constructor, debe saberlo. De lo contrario, diría "¿Por qué no utilizo un constructor para inicializar mis variables estáticas?"
Michael
0

El bloque de código estático permite inicializar los campos con más de una instrucción, inicializar campos en un orden diferente de las declaraciones y también podría usarse para la inicialización condicional.

Más específicamente,

static final String ab = a+b;
static final String a = "Hello,";
static final String b = ", world";

no funcionará porque ayb se declaran después de ab.

Sin embargo, podría usar un init estático. bloquear para superar esto.

static final String ab;
static final String a;
static final String b;

static {
  b = ", world";
  a = "Hello";
  ab = a + b;
}

static final String ab;
static final String a;
static final String b;

static {
  b = (...) ? ", world" : ", universe";
  a = "Hello";
  ab = a + b;
}
algolicioso
fuente
3
Si bien lo que está diciendo es cierto, no demuestra la necesidad de un bloque inicializador estático. Puede mover su abdeclaración debajo de la declaración de b.
gawi
0

Un bloque de inicialización estático es útil si desea inicializar tipos estáticos de clase especificados, antes del primer uso de la clase. El uso posterior no invocará ningún bloque de inicialización estático. Es lo contrario de los inicializadores de instancia, que inicializan miembros de instancia.

Remario
fuente
0

Cuando desee evaluar una expresión determinada durante el tiempo de carga de la clase, puede hacer uso del bloque estático, pero recuerde:

Debe manejar una excepción en un bloque estático, lo que significa que no puede lanzar una excepción desde un bloque estático.

I'm_Pratik
fuente