2012-07-24 17 views
7

Ho appena trascorso mezz'ora a capire questa cosa, sono riuscito a risolvere il mio codice, ma non capisco completamente cosa sta succedendo e mi chiedevo se qualcuno potesse far luce su di esso.Inizializzazione del campo statico Java

Ho una classe di , che contiene alcuni campi statici (un endpoint di connessione al database, ad esempio) utilizzati da vari altri programmi in base all'attività in corso. Essenzialmente una biblioteca.

Ecco come appariva in precedenza (mentre era ancora rotto);

//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 
    } 
} 

Così brevemente, io sto usando il metodo spawnDBConnection statico() per assegnare un valore ad entrambi myDBConnection e myDBIndex. Funziona perfettamente, la prima linea di uscita dal mio programma è sempre "connessione al database completata", né myDBConnection o myDBIndex sono nulli alla fine del metodo spawnDBConnection(), tutto è come dovrebbe essere.

Il mio programma esterno si presenta così;

//DoSomethingUsefulWithTheDatabase.java 
public final class DoSomethingUsefulWithTheDatabase { 

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

Questa chiamata a searchDB avviene dopo la spawnDBConnection ha finito, ho usato l'uscita standard ampiamente per mostrare questo. Tuttavia, una volta all'interno del metodo searchDB, il valore di myDBIndex è nullo! È un campo statico e non è nullo alla fine di spawnDBConnection, non sono stati effettuati altri assegnamenti e ora è nullo :(

La semplice soluzione era rimuovere "= null" in modo che la dichiarazione del campo ora appaia simili;

private static DBIndex myDBIndex; 

Perché che fanno la differenza sto accuratamente confuso da questo

+4

considerare la possibilità di la tua statistica 'finale'. Sarai costretto ad assegnarli esattamente una volta, eliminando questo tipo di sorpresa. –

+4

Questo è un incubo terribile-antipattern quello che stai facendo qui. Accoppia l'inizializzazione della classe per l'acquisizione di una connessione al database. –

+0

Non inizializzare in modo statico DBConnection. Cosa succede se muore myDBConnection, hai intenzione di iniziare a utilizzare DbUtils2 nel tuo codice? –

risposta

13

Questo perché l'assegnazione di null per myDBIndex è fatto dopo

private static DBConnection myDBConnection = spawnDBConnection(); 

esempio prevale l'assegnazione in spawnDBConnection

La sequenza è:

  1. dichiarano i campi myDBConnection, myDBIndex
  2. inizializzazione myDBConnection = spawnDBConnection();

    che comprende chiamando spawnDBConnection e assegnazione del valore di ritorno per myDBConnection

  3. Inizializza myDBIndex (con null)

Nel secondo esempio, il terzo passaggio non esiste.

+0

Grazie per aver chiarito questo, ora ha perfettamente senso. Per qualche ragione ho avuto in testa che qualsiasi chiamata di metodo sarebbe avvenuta dopo incarichi "semplici". – lynks

1

questo è ciò che accade nel generato blocco static initalizer:

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

Spero che ora sia chiaro.

7

Perché questo ha fatto la differenza? Sono completamente confuso da questo.

L'inizializzatore di spawnDBConnection era in esecuzione, quindi l'inizializzatore per myDBIndex era in esecuzione. L'inizializzatore per myDBIndex imposta il valore su null. Poiché questo è accaduto dopospawnDBConnection impostarlo su un valore non nullo, il risultato finale era che era nullo.

Provare a non farlo - è strano per un metodo chiamato da un inizializzatore statico per impostare altre variabili statiche.

+0

Grazie per la risposta, sapevo che quando stavo scrivendo che inizializzare una variabile statica all'interno di un'altra era una cosa strana da fare, stavo solo buttando il codice insieme per alcuni test rapidi. – lynks

0

Per quanto riguarda ne so, se si definisce il metodo prima che i vostri campi funziona, al momento dell'inizializzazione, classe viene analizzato da cima:

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); 
    } 
} 

uscita:

database connection completed 
INIT 
Problemi correlati