Según tengo entendido, el "bloque de inicialización estática" se usa para establecer valores de campo estático si no se puede hacer en una línea.
Pero no entiendo por qué necesitamos un bloque especial para eso. Por ejemplo, declaramos un campo como estático (sin una asignación de valor). Y luego escriba varias líneas del código que generan y asignan un valor al campo estático declarado anteriormente.
¿Por qué necesitamos estas líneas en un bloque especial como static {...}
:?
{...}
vsstatic {...}
. (en cuyo caso Jon Skeet definitivamente respondió su pregunta mucho mejor)Respuestas:
El bloque no estático:
Se llama cada vez que se construye una instancia de la clase. El bloque estático solo se llama una vez , cuando se inicializa la clase, sin importar cuántos objetos de ese tipo cree.
Ejemplo:
Esto imprime:
fuente
Si no estuvieran en un bloque de inicialización estática, ¿dónde estarían? ¿Cómo declararía una variable que solo debía ser local para los propósitos de inicialización y distinguirla de un campo? Por ejemplo, ¿cómo te gustaría escribir:
Si
first
ysecond
no estaban en un bloque, se verían como campos. Si estuvieran en un bloque sinstatic
delante, eso contaría como un bloque de inicialización de instancia en lugar de un bloque de inicialización estático, por lo que se ejecutaría una vez por instancia construida en lugar de una vez en total.Ahora, en este caso particular, podría usar un método estático en su lugar:
... pero eso no funciona cuando hay varias variables que desea asignar dentro del mismo bloque, o ninguna (por ejemplo, si solo desea registrar algo, o tal vez inicializar una biblioteca nativa).
fuente
private static int widgets = 0; static{widgets = 2;}
private static int widgets = 0; static{widgets = 2;}
descubrí que la asignación '=' ocurre en orden, lo que significa que el '' 'puesto primero se asignará primero. El ejemplo anterior le dará a los 'widgets' un valor de 2. (PS no sabía que los comentarios solo se pueden editar en 5 minutos ...)Aquí hay un ejemplo:
El código en la sección o secciones "estáticas" se ejecutará en el momento de la carga de la clase, antes de que se construyan instancias de la clase (y antes de que se llame a cualquier método estático desde otro lugar). De esa manera, puede asegurarse de que los recursos de la clase estén listos para usar.
También es posible tener bloques de inicializador no estáticos. Esos actúan como extensiones del conjunto de métodos constructores definidos para la clase. Se parecen a los bloques de inicializador estático, excepto que la palabra clave "estática" se omite.
fuente
También es útil cuando en realidad no desea asignar el valor a nada, como cargar alguna clase solo una vez durante el tiempo de ejecución.
P.ej
Oye, hay otro beneficio, puedes usarlo para manejar excepciones. Imagine que
getStuff()
aquí arroja unException
que realmente pertenece en un bloque de captura:entonces un
static
inicializador es útil aquí. Puedes manejar la excepción allí.Otro ejemplo es hacer cosas después que no se pueden hacer durante la asignación:
Para volver al ejemplo del controlador JDBC, cualquier controlador JDBC decente también utiliza el
static
inicializador para registrarse en elDriverManager
. También vea esto y esta respuesta.fuente
Yo diría que
static block
es solo azúcar sintáctico. No hay nada que puedas hacer con elstatic
bloqueo y no con nada más.Para reutilizar algunos ejemplos publicados aquí.
Este código podría reescribirse sin usar
static
initialiser.Método # 1: con
static
Método # 2: sin
static
fuente
Hay algunas razones reales por las que se requiere que exista:
static final
miembros cuya inicialización podría generar una excepciónstatic final
miembros con valores calculadosLas personas tienden a usar
static {}
bloques como una forma conveniente de inicializar cosas de las que depende la clase también en el tiempo de ejecución, como garantizar que se cargue una clase en particular (por ejemplo, controladores JDBC). Eso se puede hacer de otras maneras; sin embargo, las dos cosas que menciono anteriormente solo se pueden hacer con una construcción como elstatic {}
bloque.fuente
Puede ejecutar bits de código una vez para una clase antes de construir un objeto en los bloques estáticos.
P.ej
fuente
Es un error común pensar que un bloque estático solo tiene acceso a campos estáticos. Para esto, me gustaría mostrar a continuación el código que utilizo con bastante frecuencia en proyectos de la vida real (copiado parcialmente de otra respuesta en un contexto ligeramente diferente):
Aquí el inicializador se utiliza para mantener un índice (
ALIAS_MAP
), para asignar un conjunto de alias al tipo de enumeración original. Está destinado a ser una extensión del método valueOf incorporado proporcionado por elEnum
mismo.Como puede ver, el inicializador estático accede incluso al
private
campoaliases
. Es importante comprender que elstatic
bloque ya tiene acceso a lasEnum
instancias de valor (pENGLISH
. Ej .). Esto se debe al orden de inicialización y ejecución en el caso de losEnum
tipos , como si losstatic private
campos se hubieran inicializado con instancias antes destatic
que se llamaran los bloques:Enum
constantes que son campos estáticos implícitos. Esto requiere que el constructor Enum y los bloques de instancia, y la inicialización de la instancia también ocurran primero.static
bloque e inicialización de campos estáticos en el orden de ocurrencia.Es
static
importante tener en cuenta esta inicialización fuera de orden (constructor antes del bloque). También sucede cuando inicializamos campos estáticos con las instancias de manera similar a un Singleton (simplificaciones hechas):Lo que vemos es el siguiente resultado:
Claro es que la inicialización estática en realidad puede ocurrir antes del constructor, e incluso después:
Simplemente acceder a Foo en el método principal hace que se cargue la clase y se inicie la inicialización estática. Pero como parte de la inicialización estática, nuevamente llamamos a los constructores para los campos estáticos, después de lo cual reanuda la inicialización estática y completa el constructor llamado desde el método principal. Situación bastante compleja para la que espero que en la codificación normal no tengamos que lidiar.
Para obtener más información sobre esto, consulte el libro " Java eficaz ".
fuente
aliases
no significa que el bloque estático pueda acceder a miembros no estáticos.aliases
se accede a través de losLanguage
valores devueltos por elvalues()
método / static / . Como mencionas, el hecho de que las variables enum ya estén disponibles en ese punto es un bit inusual: los miembros no estáticos de las clases regulares no serían accesibles en esta situación.class Foo { static final Foo Inst1; static final Foo Inst2; static{ Inst1 = new Foo("Inst1"); Inst2 = new Foo("Inst2"); } static { System.out.println("Inst1: " + Inst1.member); System.out.println("Inst2: " + Inst2.member); } private final String member; private Foo(String member){ this.member = member; } }
El código anterior no es diferente del ejemplo enum y aún permite el acceso a la variable de instancia dentro del bloque estáticoEnum
. Es la mejor manera de garantizar que estamos apuntando a instancias singulares '- vea aquí . Y a sus puntos, he realizado varias actualizaciones.Si sus variables estáticas necesitan establecerse en tiempo de ejecución, entonces un
static {...}
bloque es muy útil.Por ejemplo, si necesita establecer el miembro estático en un valor que se almacena en un archivo de configuración o base de datos.
También es útil cuando desea agregar valores a un
Map
miembro estático , ya que no puede agregar estos valores en la declaración inicial del miembro.fuente
Entonces tiene un campo estático (también se llama "variable de clase" porque pertenece a la clase en lugar de a una instancia de la clase; en otras palabras, está asociado con la clase en lugar de con cualquier objeto) y desea inicializarlo. Entonces, si NO desea crear una instancia de esta clase y desea manipular este campo estático, puede hacerlo de tres maneras:
1- Solo inicialízalo cuando declares la variable:
2- Tener un bloque de inicialización estático:
3- Tenga un método de clase (método estático) que acceda a la variable de clase y la inicialice: esta es la alternativa al bloque estático anterior; puedes escribir un método estático privado:
Ahora, ¿por qué usaría un bloque de inicialización estático en lugar de métodos estáticos?
Realmente depende de lo que necesita en su programa. Pero debe saber que el bloque de inicialización estático se llama una vez y la única ventaja del método de clase es que pueden reutilizarse más adelante si necesita reinicializar la variable de clase.
Digamos que tiene una matriz compleja en su programa. Lo inicializa (usando para loop, por ejemplo) y luego los valores de esta matriz cambiarán a lo largo del programa, pero luego, en algún momento, desea reiniciarlo (volver al valor inicial). En este caso, puede llamar al método estático privado. En caso de que no necesite en su programa reiniciar los valores, simplemente puede usar el bloque estático y no necesita un método estático ya que no lo usará más adelante en el programa.
Nota: los bloques estáticos se llaman en el orden en que aparecen en el código.
Ejemplo 1:
Ejemplo 2
fuente
Como complemento, como dijo @Pointy
Se supone que se agrega
System.loadLibrary("I_am_native_library")
al bloque estático.Garantizará que no se llame a ningún método nativo antes de que la biblioteca relacionada se cargue en la memoria.
Según loadLibrary del oráculo :
Entonces, inesperadamente, poner System.loadLibrary no se usa para evitar que la biblioteca se cargue varias veces.
fuente
Primero debe comprender que sus propias clases de aplicación se instancian en
java.class.Class
objetos durante el tiempo de ejecución. Esto es cuando se ejecutan sus bloques estáticos. Entonces realmente puedes hacer esto:e imprimiría "myInt is 1" a la consola. Tenga en cuenta que no he instanciado ninguna clase.
fuente
fuente
el bloque estático se usa para cualquier tecnología para inicializar el miembro de datos estáticos de forma dinámica, o podemos decir que para la inicialización dinámica del miembro de datos estático se está utilizando el bloque estático ... Debido a la inicialización del miembro de datos no estáticos, tenemos un constructor pero no tenemos cualquier lugar donde podamos inicializar dinámicamente miembros de datos estáticos
Ahora mi static x int se inicializará dinámicamente ... porque cuando el compilador irá a Solution.x cargará la clase de solución y la carga de bloque estático en el momento de carga de la clase ... para que podamos inicializar dinámicamente ese miembro de datos estáticos ...
}
fuente