2012-07-24 140 views
7

我剛剛花了半小時弄清楚這件事情,我已經設法修復了我的代碼,但是我並不完全理解正在發生的事情,並想知道是否有人可以闡明它。Java靜態字段初始化

我有一個utils的類型的類,它包含由根據手頭的任務其他多種程序使用了一些靜態字段(例如數據庫連接的端點)。本質上是一個圖書館。

這是它以前的樣子(雖然還是壞了);

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

所以簡單地說,我使用的是靜態spawnDBConnection()方法來分配一個值都myDBConnectionmyDBIndex。這是完美的,我的程序中的第一個輸出行始終是「數據庫連接已完成」,在spawnDBConnection()方法結束時,myDBConnection或myDBIndex都不爲null,所有內容都應該如此。

我的外部程序看起來像這樣;

//DoSomethingUsefulWithTheDatabase.java 
public final class DoSomethingUsefulWithTheDatabase { 

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

這次調用searchDB發生在spawnDBConnection結束後,我已經使用了標準輸出廣泛,顯示這一點。但是,一旦進入searchDB方法,myDBIndex的值就是null!它是一個靜態字段,並且在spawnDBConnection結束時它不爲空,現在沒有其他任務了,現在它是空的:(

簡單的修復方法是刪除「= null」,所以現在的字段聲明看起來像等;

private static DBIndex myDBIndex; 

爲什麼有所作爲,我徹底被這個迷惑

+4

考慮制定你的靜態'最後'。你將被迫分配一次,消除這種驚喜。 – 2012-07-24 12:52:47

+4

這是一個可怕的噩夢 - 反模式你在這裏做什麼。您將類初始化耦合到數據庫連接的獲取。 – 2012-07-24 12:54:28

+0

您不應靜態初始化DBConnection。如果myDBConnection死了,你會在代碼中開始使用DbUtils2嗎? – 2012-07-24 12:58:32

回答

13

這是因爲nullmyDBIndex的分配後

private static DBConnection myDBConnection = spawnDBConnection(); 

例如做覆蓋在spawnDBConnection

順序分配是:

  1. 申報領域myDBConnectionmyDBIndex
  2. 初始化myDBConnection = spawnDBConnection();

    ,其中包括呼叫spawnDBConnection和返回值賦值給myDBConnection

  3. 初始化myDBIndex(with null)

在第二個例子中,第三步不存在。

+0

感謝您澄清這一點,它現在非常有意義。出於某種原因,我認爲任何方法調用都會在「簡單」分配後發生。 – lynks 2012-07-24 13:21:10

1

這是產生static initalizer塊會發生什麼:

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

我希望現在很清楚。

7

爲什麼這會有所作爲?我完全被這個弄糊塗了。

spawnDBConnection的初始化正在運行,然後myDBIndex初始化正在運行。 myDBIndex的初始化程序將該值設置爲null。當發生後spawnDBConnection將其設置爲非空值時,最終結果爲空。

儘量不要這麼做 - 對於靜態初始化程序調用的方法來設置其他靜態變量很奇怪。

+0

感謝您的回覆,我知道當我寫這篇文章時,在另一個靜態變量中初始化一個靜態變量是一件很奇怪的事情,我只是將代碼放在一起進行一些快速測試。 – lynks 2012-07-24 13:10:48

0

至於我所知,如果你的領域之前定義你的方法它的工作,在初始化時,類是從頂部解析:

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

輸出:

database connection completed 
INIT