【问题标题】:Java: ExceptionInInitializerError on program startupJava:程序启动时出现ExceptionInInitializerError
【发布时间】:2012-08-11 09:52:33
【问题描述】:

在启动时,我的程序立即抛出 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...

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

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

编辑:如果我将调用“loadCursor”的静态光标对象移动到不同的类,似乎不会引发异常。什么?

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

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

【问题讨论】:

  • 你能显示更多代码吗?你能贴一个SSCCE吗?
  • 你想发布整个课程吗?
  • 是或重现问题的sn-p。
  • 目前我唯一能找到的是stackoverflow.com/questions/2547713/…,但这是一个静态方法而不是构造函数,所以它似乎不适用。
  • Pssh...SimpleDateFormat不是线程安全的。绝对不建议将其设为类变量。而是在本地方法范围内创建它。

标签: java static nullpointerexception static-methods


【解决方案1】:

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

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

很明显,A$ 中的一些静态字段初始化在 dateform 初始化并调用 loadCursor 之前执行,然后在逻辑上失败,NullPointerExceptiondate 和 @987654332 @ 未初始化。

问题是您已将初始化 Cursor 的代码放在初始化 dateform 对象的代码之前。在声明时赋值的静态字段按照声明顺序初始化,按照Section §8.3.2.1 of the Java Language Specification

如果您阅读详细的初始化过程,尤其是Section §12.4.2.9,您会发现...

接下来,按照文本顺序执行类的类变量初始化程序和静态初始化程序,或者接口的字段初始化程序,就好像它们是一个单独的块一样。


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

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

static Cursor loadCursor() {
  ...
  errorMessage("...");
  ...
}

loadCursor 必须dateform 被初始化之前调用。


您的示例没有产生 'error'(嗯?)的原因是因为这两种方法都没有引用尚未初始化的字段。如果您想要完全没有错误的等效行为,请参阅以下内容(可以看到运行here):

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

可以看到输出如下。

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

【讨论】:

  • 哦,我想我现在明白了。我会在方法声明后尝试调用 loadCursor
  • 嗯,这很有趣。它解决了这个问题。我以前从未遇到过这个问题。哼……哦,好吧。感谢您的解决方案!我想我现在要多尝试一下静态字段,看看我能做什么,不能做什么。
  • @MrDoctorProfessorTyler,类按照程序执行中遇到依赖的顺序进行初始化,包括类初始化。它从你的主要课程开始。如果这个类有引用类 A 的代码,那么 A 将开始初始化。如果 this 又引用了 B 类,则 B 的初始化将开始。如果 B 引用 A,则 A 中的代码可以在 A 完全初始化之前运行。这个问题是由于试图在静态初始化中做太多的工作造成的。
  • @MrDoctorProfessorTyler 您发布的示例不会重现问题。查看gist.github.com/3355609 以查看导致它的示例。
  • @MrDoctorProfessorTyler 我已经更新了我的帖子,以包含一个相关的简单示例来演示该问题。
【解决方案2】:

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

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

你可能需要做一些类似的事情

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

或类似的:P

【讨论】:

  • 这将产生一个ArrayIndexOutOfBoundsException,而不是NullPointerException
  • 不,但这是个好建议。 errorMessage 方法中唯一返回 null 的是日期和表单,它们都是在方法之外静态声明的
  • @veer 这是我唯一不能不工作的事情——但你是对的
猜你喜欢
  • 1970-01-01
  • 2015-11-09
  • 1970-01-01
  • 2015-01-04
  • 2015-04-15
  • 2011-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多