Java:程序启动时的ExceptionInInitializerError

时间:2012-08-15 03:03:27

标签: java static nullpointerexception static-methods

启动时,我的程序会立即抛出ExceptionInInitializerError。来源来自这种方法:

public static void errorMessage(String input) {
    System.err.println("[ERROR] " + form.format(date) + " - " + Thread.currentThread().getStackTrace()[3].getClassName() + ": " + input);
}

我打印出字符串的不同部分,发现只有在调用form.format(date)时才会抛出错误。它说它是空的。唯一的问题是,日期和表单都在这个方法的正上方静态声明:

public static Date date = new Date();
public static DateFormat form = new SimpleDateFormat("HH:mm:ss");

在修复一些小错误之后,错误突然开始被抛出。我不知道出了什么问题或者出了什么问题。我的意思是,我在同一个类中调用静态声明的变量。从技术上讲,它们不应该是空的,但它们是。任何人有任何想法,为什么它会抛出这个错误?这是控制台输出:

java.lang.ExceptionInInitializerError
at A$$OpSystem.getOperatingSystem(A$.java:98)
at A_.<clinit>(A_.java:19)
Caused by: java.lang.NullPointerException
at A$.errorMessage(A$.java:72)
at A$.loadCursor(A$.java:84)
at A$.<clinit>(A$.java:62)
... 2 more
Exception in thread "main" 

顺便说一句,A $ .OpSystem.getOperatingSystem只在那里显示,因为它调用A $ .errorMessage ......

之前我遇到过这个问题,只是当一个静态声明的变量在被调用时实际上从未被声明为空时。现在它不应该是null,但它确实是。所以我不知道是什么导致了它。想法?

但我想这是一个了解静态变量如何实际加载的好时机......

编辑:如果我将调用'loadCursor'的静态Cursor对象移动到另一个类,似乎没有抛出异常。什么?

我对这种情况进行了测试但没有返回错误?

public class StaticMethodTesting {

public static int i = getInt();

public static int getInt() {
    return getAnotherInt();
}

public static int getAnotherInt() {
    return 0;
}

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

2 个答案:

答案 0 :(得分:7)

检查异常跟踪后......

at A$.errorMessage(A$.java:72)
at A$.loadCursor(A$.java:84)
at A$.< clinit>(A$.java:62)

很明显A$中的某些静态字段初始化正在dateform的初始化之前执行,并且正在调用loadCursor,然后NullPointerException逻辑失败并date 1}} formCursor未初始化。

问题在于,您已经在初始化dateform对象之前放置了初始化static Cursor cursor = loadCursor(); static Date date = new Date(); static DateFormat form = new SimpleDateFormat("HH:mm:ss"); static Cursor loadCursor() { ... errorMessage("..."); ... } 的代码。声明时具有分配的静态字段按声明顺序初始化,按Section §8.3.2.1 of the Java Language Specification

如果你阅读详细的初始化过程,特别是Section §12.4.2.9,你会发现......

  

接下来,以文本顺序执行类的类变量初始值设定项和静态初始值设定项,或接口的字段初始值设定项,就像它们是单个块一样。


所以,你可能会做这样的事情:

loadCursor

date必须 才能在form之前调用<{1}},并且import java.util.Random; public final class Example { /* note if the below read: static final int value = rand.nextInt(), this would be considered an illegal forward reference to rand */ private static final int value = next(); private static final Random rand = new Random(); private static int next() { return rand.nextInt(); } public static void main(final String[] argv) { } } 如果您希望这样做,则必须<{1}}。


你的例子没有产生'错误'(是吧?)的原因是因为这两个方法都没有引用尚未初始化的字段。如果您希望等效行为绝不是错误,请参阅以下内容(可以看到运行here):

Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.NullPointerException
        at Example.next(Example.java:11)
        at Example.<clinit>(Example.java:7)

可以看出输出如下。

{{1}}

答案 1 :(得分:0)

我想你会发现问题发生在这里

Thread.currentThread().getStackTrace()[3].getClassName() 

您可能需要做更像

的事情
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
String className = stackTrace[Math.min(3, stackTrace.length - 1)].getClassName();

或类似:P