Pregunta

Por lo que entendía la "inicialización estática bloque" se utiliza para establecer los valores de campo estático si no puede hacerse en una sola línea.

Pero no entiendo por qué necesitamos un bloque especial para eso.Por ejemplo declaramos un campo estático (sin una asignación de valor).Y, a continuación, escribir varias líneas de código que genera y asigna un valor a la anterior declaró campo estático.

¿Por qué necesitamos estas líneas en un bloque especial como: static {...}?

¿Fue útil?

Solución

La bloque no estático:

{
    // Do Something...
}

se llama a cada vez una instancia de la clase se construye. El bloque estático sólo se obtiene la llamada una vez , cuando la clase en sí se inicia, no importa cuántos objetos de ese tipo se crea.

Ejemplo:

public class Test {

    static{
        System.out.println("Static");
    }

    {
        System.out.println("Non-static block");
    }

    public static void main(String[] args) {
        Test t = new Test();
        Test t2 = new Test();
    }
}

Esto imprime:

Static
Non-static block
Non-static block

Otros consejos

Si no estaban en un bloque de inicialización estática, donde serían? ¿Cómo se declara una variable que sólo estaba destinado a ser local a efectos de inicialización, y distinguirlo de un campo? Por ejemplo, ¿cómo que desee escribir:

public class Foo {
    private static final int widgets;

    static {
        int first = Widgets.getFirstCount();
        int second = Widgets.getSecondCount();
        // Imagine more complex logic here which really used first/second
        widgets = first + second;
    }
}

Si first y second no estaban en un bloque, se vería como campos. Si estaban en un bloque sin static en frente de ella, que contaría como un bloque de inicialización de instancia en lugar de un bloque de inicialización estática, por lo que se ejecutará una vez por ejemplo calculado, en lugar de una vez en total.

Ahora bien, en este caso particular, se puede usar un método estático en su lugar:

public class Foo {
    private static final int widgets = getWidgets();

    static int getWidgets() {
        int first = Widgets.getFirstCount();
        int second = Widgets.getSecondCount();
        // Imagine more complex logic here which really used first/second
        return first + second;
    }
}

... pero eso no funciona cuando hay múltiples variables que desea asignar en el mismo bloque, o ninguno (por ejemplo, si sólo desea registrar algo - o tal vez inicializar una biblioteca nativa).

Este es un ejemplo:

  private static final HashMap<String, String> MAP = new HashMap<String, String>();
  static {
    MAP.put("banana", "honey");
    MAP.put("peanut butter", "jelly");
    MAP.put("rice", "beans");
  }

El código en la sección "estática" (s) será ejecutado en tiempo de carga de clases, antes se construyen todas las instancias de la clase (y antes de cualquiera de los métodos estáticos son llamados desde otros lugares). De esa manera usted puede asegurarse de que los recursos de clase están listos para su uso.

También es posible tener bloques de inicializador no estáticos. Los que actúan como extensiones para el conjunto de métodos constructores definidos para la clase. Parecen bloques inicializador estático, excepto la palabra clave "estática" se queda fuera.

También es útil cuando realmente no desea asignar el valor a cualquier cosa, como la carga de alguna clase sólo una vez durante el tiempo de ejecución.

por ejemplo.

static {
    try {
        Class.forName("com.example.jdbc.Driver");
    } catch (ClassNotFoundException e) {
        throw new ExceptionInInitializerError("Cannot load JDBC driver.", e);
    }
}

Oye, hay otro beneficio, que se puede utilizar para manejar excepciones. Imaginar que aquí getStuff() lanza una Exception que realmente pertenece en un bloque catch:

private static Object stuff = getStuff(); // Won't compile: unhandled exception.

a continuación, un inicializador static es útil aquí. Puede manejar la excepción allí.

Otro ejemplo es hacer cosas después que no se puede hacer durante la asignación:

private static Properties config = new Properties();

static {
    try { 
        config.load(Thread.currentThread().getClassLoader().getResourceAsStream("config.properties");
    } catch (IOException e) {
        throw new ExceptionInInitializerError("Cannot load properties file.", e);
    }
}

Para volver al ejemplo de controlador JDBC, cualquier controlador JDBC decente en sí también hace uso del inicializador static registrarse a sí mismo en el DriverManager. También ver este y esta respuesta .

Yo diría static block es sólo azúcar sintáctico. No hay nada que podría hacer con el bloque static y no con cualquier otra cosa.

Para volver a utilizar algunos ejemplos publicados aquí.

Esta pieza de código podría ser reescrita sin utilizar initialiser static.

Método # 1: Con static

private static final HashMap<String, String> MAP;
static {
    MAP.put("banana", "honey");
    MAP.put("peanut butter", "jelly");
    MAP.put("rice", "beans");
  }

Método # 2: sin static

private static final HashMap<String, String> MAP = getMap();
private static HashMap<String, String> getMap()
{
    HashMap<String, String> ret = new HashMap<>();
    ret.put("banana", "honey");
    ret.put("peanut butter", "jelly");
    ret.put("rice", "beans");
    return ret;
}

Hay algunas razones reales que se requiere para existir:

  1. inicializar miembros static final cuya inicialización podría lanzar una excepción
  2. inicializar miembros static final con los valores calculados

La gente tiende a utilizar bloques static {} como una manera conveniente para inicializar las cosas que la clase depende en el tiempo de ejecución, así como asegurar - esa clase en particular se carga (por ejemplo, controladores JDBC). Eso se puede hacer de otras maneras; sin embargo, las dos cosas que menciono anteriormente solamente se puede hacer con un constructo como el bloque static {}.

Puede ejecutar bits de código una vez para una clase antes de un objeto se construye en los bloques estáticos.

por ejemplo.

class A {
  static int var1 = 6;
  static int var2 = 9;
  static int var3;
  static long var4;

  static Date date1;
  static Date date2;

  static {
    date1 = new Date();

    for(int cnt = 0; cnt < var2; cnt++){
      var3 += var1;
    }

    System.out.println("End first static init: " + new Date());
  }
}

Es un error común pensar que un bloque estático sólo tiene acceso a los campos estáticos.Para esto me gustaría mostrar debajo de la pieza de código que estoy bastante a menudo su uso en proyectos de la vida real (copiado en parte, de otra respuesta en un contexto ligeramente distinto):

public enum Language { 
  ENGLISH("eng", "en", "en_GB", "en_US"),   
  GERMAN("de", "ge"),   
  CROATIAN("hr", "cro"),   
  RUSSIAN("ru"),
  BELGIAN("be",";-)");

  static final private Map<String,Language> ALIAS_MAP = new HashMap<String,Language>(); 
  static { 
    for (Language l:Language.values()) { 
      // ignoring the case by normalizing to uppercase
      ALIAS_MAP.put(l.name().toUpperCase(),l); 
      for (String alias:l.aliases) ALIAS_MAP.put(alias.toUpperCase(),l); 
    } 
  } 

  static public boolean has(String value) { 
    // ignoring the case by normalizing to uppercase
    return ALIAS_MAP.containsKey(value.toUpper()); 
  } 

  static public Language fromString(String value) { 
    if (value == null) throw new NullPointerException("alias null"); 
    Language l = ALIAS_MAP.get(value); 
    if (l == null) throw new IllegalArgumentException("Not an alias: "+value); 
    return l; 
  } 

  private List<String> aliases; 
  private Language(String... aliases) { 
    this.aliases = Arrays.asList(aliases); 
  } 
} 

Aquí el inicializador se utiliza para mantener un índice (ALIAS_MAP), para asignar un conjunto de alias de nuevo a la original de tipo enum.Está pensado como una extensión de la incorporada en el método valueOf proporcionados por el Enum sí.

Como se puede ver, el inicializador estático accesos incluso la private campo aliases.Es importante entender que la static bloque ya tiene acceso a la Enum valor instancias (por ejemplo, ENGLISH).Esto es debido a que el orden de inicialización y ejecución en el caso de Enum tipos de, como si el static private los campos se han iniciado con las instancias antes de la static los bloques han sido llamados:

  1. El Enum las constantes que están implícitos los campos estáticos.Esto requiere que el constructor de la Enumeración y de la instancia de los bloques, y la inicialización de instancia para que se produzca en primer lugar así.
  2. static el bloque y la inicialización de los campos estáticos en el orden de ocurrencia.

Esta fuera de la orden de inicialización (constructor antes de static block) es importante tener en cuenta.También sucede cuando inicializamos los campos estáticos con las instancias de manera similar a un Singleton (simplificaciones hechas):

public class Foo {
  static { System.out.println("Static Block 1"); }
  public static final Foo FOO = new Foo();
  static { System.out.println("Static Block 2"); }
  public Foo() { System.out.println("Constructor"); }
  static public void main(String p[]) {
    System.out.println("In Main");
    new Foo();
  }
}

Lo que vemos es la siguiente resultado:

Static Block 1
Constructor
Static Block 2
In Main
Constructor

Claro es que la inicialización estática en realidad puede suceder antes de el constructor, e incluso después de:

El simple acceso a Foo en el método main, hace que la clase se va a cargar y la inicialización estática para empezar.Pero como parte de la inicialización Estática volvemos a llamar a los constructores de los campos estáticos, después de lo cual se reanuda la inicialización estática, y completa el constructor llama desde dentro del método main.Más bien compleja situación por la que espero que en condiciones normales de codificación no tendríamos que lidiar con.

Para más información sobre esto, vea el libro "Efectivos De Java".

Si las variables estáticas se deben establecer en tiempo de ejecución a continuación, un bloque static {...} es muy útil.

Por ejemplo, si tiene que establecer el miembro estático a un valor que se almacena en un archivo de configuración o base de datos.

También es útil cuando se desea añadir valores a un miembro de Map estática que no se puede agregar estos valores en la declaración de miembro inicial.

Así que hay un campo estático (también se llama "variable de clase", ya que pertenece a la clase en lugar de a una instancia de la clase, es decir que está asociado a la clase más que con cualquier objeto) y que desea inicializarlo. Así que si usted no desea crear una instancia de esta clase y que desea manipular este campo estático, puede hacerlo de tres maneras:

1- Sólo inicializarlo cuando se declara la variable:

static int x = 3;

2- Tener un bloque de inicialización estática:

static int x;

static {
 x=3;
}

3- tener un método de clase (método estático) que accede a la variable de clase y lo inicializa: esta es la alternativa al bloque estático anteriormente; se puede escribir un método estático privado:

public static int x=initializeX();

private static int initializeX(){
 return 3;
}

Ahora ¿para qué usar el bloque de inicialización estática en lugar de los métodos estáticos?

Es realmente depende de lo que necesita en su programa. Pero hay que saber que el bloque de inicialización estática se llama una vez y la única ventaja del método de clase es que pueden ser reutilizados más adelante si es necesario reinicializar la variable de clase.

digamos que tiene una matriz compleja en su programa. Inicializar (utilizando bucle for , por ejemplo) y luego los valores de esta matriz cambiarán a lo largo del programa, pero entonces en algún momento desea reinicializar que (volver al valor inicial). En este caso se puede llamar al método estático privado. En caso de que no necesita en su programa para reinicializar los valores, sólo puede utilizar el bloque estático y sin necesidad de un método estático ya que eres su uso no va más adelante en el programa.

Nota: los bloques estáticos son llamados en el orden en que aparecen en el código.

Ejemplo 1:

class A{
 public static int a =f();

// this is a static method
 private static int f(){
  return 3;
 }

// this is a static block
 static {
  a=5;
 }

 public static void main(String args[]) {
// As I mentioned, you do not need to create an instance of the class to use the class variable
  System.out.print(A.a); // this will print 5
 }

}

Ejemplo 2:

class A{
 static {
  a=5;
 }
 public static int a =f();

 private static int f(){
  return 3;
 }

 public static void main(String args[]) {
  System.out.print(A.a); // this will print 3
 }

}

Como complementario, como @Pointy dijo

  

El código en la sección "estática" (s) se ejecutará con carga de clases   tiempo, antes se construyen todas las instancias de la clase (y antes   cualquiera de los métodos estáticos son llamados desde otros lugares).

Se supone que añadir System.loadLibrary("I_am_native_library") en bloque estático.

static{
    System.loadLibrary("I_am_a_library");
}

Además, garantizará ningún método nativo llamarse antes de la biblioteca correspondiente se carga en la memoria.

Según loadLibrary de Oracle :

  

Si este método se llama más de una vez con el mismo nombre de la biblioteca,   las llamadas segunda y subsiguientes se ignoran.

Así que de manera inesperada, poniendo System.loadLibrary no se utiliza para evitar la biblioteca pueden cargar múltiples veces.

En primer lugar, hay que entender que sus clases de la aplicación sí se crean instancias de java.class.Class objetos en tiempo de ejecución. Esto es cuando se corrieron sus bloques estáticos. Así que en realidad se puede hacer esto:

public class Main {

    private static int myInt;

    static {
        myInt = 1;
        System.out.println("myInt is 1");
    }

    //  needed only to run this class
    public static void main(String[] args) {
    }

}

y sería imprimir "myInt es de 1" a la consola. Tenga en cuenta que no he instancia de cualquier clase.

static int B,H;
static boolean flag = true;
static{
    Scanner scan = new Scanner(System.in);
    B = scan.nextInt();
    scan.nextLine();
    H = scan.nextInt();

    if(B < 0 || H < 0){
        flag = false;
        System.out.println("java.lang.Exception: Breadth and height must be positive");
    } 
}

bloque estático se utiliza para cualquier tecnología para inicializar el miembro de datos estático en forma dinámica, o podemos decir para la inicialización dinámica del bloque estático miembro de datos estático está siendo used..Because para la inicialización miembro de datos estáticos no tenemos constructor pero no tienen ningún lugar donde podemos inicializar dinámicamente miembro de datos estático

Eg:-class Solution{
         // static int x=10;
           static int x;
       static{
        try{
          x=System.out.println();
          }
         catch(Exception e){}
        }
       }

     class Solution1{
      public static void main(String a[]){
      System.out.println(Solution.x);
        }
        }

Ahora mi static int x inicializará de forma dinámica cuando ..Bcoz compilador irá a Solution.x se cargará solución de clase y la carga estática en el bloque de carga de clases time..So podemos capaz de inicializar dinámicamente que el miembro de datos estáticos ..

}

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top