2012-07-24 23 views
7

Acabo de pasar media hora pensando en esto, he logrado arreglar mi código, pero no entiendo completamente lo que está sucediendo y me pregunto si alguien podría arrojar algo de luz sobre él.Inicialización de campo estático Java

tengo una clase tipo utils, que contiene unos campos estáticos (un punto extremo de conexión de base de datos, por ejemplo) que son utilizados por otros programas en función de la tarea en cuestión. Esencialmente una biblioteca.

Así es como se veía anteriormente (aunque todavía está roto);

//DBUtils.java 
public final class DBUtils { 

    private static DBConnection myDBConnection = spawnDBConnection(); 
    private static DBIndex myDBIndex = null; 

    private static DBConnection spawnDBConnection() { 
     //connect to the database 
     //assign a value to myDBIndex (by calling a method on the DBConnection object) <- IMPORTANT 
     //myDbIndex NOT NULL HERE 
     System.out.println("database connection completed"); 
     //return the DBConnection object 
    } 

    public static searchDB(String name) { 
     //use the myDBIndex to find a row and return it 
    } 
} 

tan brevemente, estoy usando el método spawnDBConnection estática() para asignar un valor a tanto myDBConnection y myDBIndex. Esto funciona perfectamente, la primera línea de salida de mi programa siempre es "conexión de base de datos completada", ni myDBConnection ni myDBIndex son nulos al final del método spawnDBConnection(), todo es como debería ser.

Mi programa externo se ve así;

//DoSomethingUsefulWithTheDatabase.java 
public final class DoSomethingUsefulWithTheDatabase { 

    public static void main(String args[]) { 
     DBUtils.searchDB("John Smith"); //fails with NullPointerException on myDBIndex! 
    } 
} 

Este llamado a searchDB sucede después de la spawnDBConnection ha terminado, he utilizado la salida estándar ampliamente para demostrar esto. Sin embargo, una vez dentro del método searchDB, ¡el valor de myDBIndex es nulo! Es un campo estático, y no fue nulo al final de spawnDBConnection, no se han realizado otras asignaciones, y ahora es nulo :(

La solución simple era eliminar el "= nulo", por lo que ahora se ve la declaración del campo similares;

private static DBIndex myDBIndex; 

¿por qué que marcan la diferencia que estoy completamente confundido por éste

+4

Considere hacer su estática 'final'. Te verás obligado a asignarlos exactamente una vez, eliminando este tipo de sorpresa. –

+4

Esto es una terrible pesadilla-antipattern qué estás haciendo aquí. Está acoplando la inicialización de clase a la adquisición de una conexión de base de datos. –

+0

No debe inicializar estáticamente DBConnection. ¿Qué pasa si myDBConnection se muere, vas a comenzar a usar DbUtils2 en tu código? –

Respuesta

13

Esto se debe a la asignación de null a myDBIndex se realiza después de

private static DBConnection myDBConnection = spawnDBConnection(); 

por ejemplo anula la asignación en spawnDBConnection

La secuencia es:

  1. declaran los campos myDBConnection, myDBIndex
  2. Inicializar myDBConnection = spawnDBConnection();

    que incluye llamar spawnDBConnection y asignación del valor de retorno a myDBConnection

  3. Inicializa myDBIndex (con nulo)

En el segundo ejemplo, el 3er paso no existe.

+0

Gracias por aclarar esto, tiene mucho sentido ahora. Por alguna razón, tenía en mi cabeza que cualquier llamada al método ocurriría después de asignaciones 'simples'. – lynks

1

esto es lo que sucede en el bloque static initalizer generada:

static { 
    myDBConnection = spawnDBConnection(); 
    myDBIndex = null; 
} 
?.

Espero que esté claro ahora.

7

¿Por qué eso hizo la diferencia? Estoy completamente confundido por este.

El inicializador para spawnDBConnection estaba en funcionamiento, a continuación, el inicializador para myDBIndex estaba en marcha. El inicializador para myDBIndex establece el valor en nulo. Como esto sucedió después despawnDBConnection establecerlo en un valor no nulo, el resultado final fue que era nulo.

Intente no hacer esto: es extraño que un método llamado por un inicializador estático establezca otras variables estáticas.

+0

Gracias por la respuesta, cuando escribí esto, sabía que inicializar una variable estática dentro de otra era algo raro de hacer, solo estaba lanzando código para algunas pruebas rápidas. – lynks

0

En cuanto a lo que sé, si se define el método antes de sus campos que hace el trabajo, en la inicialización, clase se analice desde la parte superior:

public class DbUtils { 
    private static String spawnDBConnection() { 
     System.out.println("database connection completed"); 
     return "INIT"; 
    } 
    private static String myDBConnection = spawnDBConnection(); 
    private static int myDBIndex = 0; 

    public static void main(final String[] args) { 
     System.out.println(myDBConnection); 
    } 
} 

Salida:

database connection completed 
INIT 
Cuestiones relacionadas