2012-07-24 107 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