Java:程序启动时的ExceptionInInitializerError

Cod*_*ler 6 java static static-methods nullpointerexception

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

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

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

public static Date date = new Date();
public static DateFormat form = new SimpleDateFormat("HH:mm:ss");
Run Code Online (Sandbox Code Playgroud)

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

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" 
Run Code Online (Sandbox Code Playgroud)

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

我之前遇到过这个问题,就是当一个静态声明的变量在被调用时实际上从未声明为null时.现在它不应该是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");
}
}
Run Code Online (Sandbox Code Playgroud)

old*_*inb 8

检查异常跟踪后...

at A$.errorMessage(A$.java:72)
at A$.loadCursor(A$.java:84)
at A$.< clinit>(A$.java:62)
Run Code Online (Sandbox Code Playgroud)

它变得清晰,在某些静态字段初始化A$时的初始化之前执行date,并form和通话loadCursor,然后在逻辑上失败,NullPointerException作为dateform不会被初始化.

问题是你已经放置了Cursor初始化你的date和初始化你的form对象的代码.根据Java语言规范的第§8.3.2.1节,在声明时具有赋值的静态字段按声明顺序初始化.

如果您阅读详细的初始化过程,特别是第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("...");
  ...
}
Run Code Online (Sandbox Code Playgroud)

loadCursor必须之前调用dateform,如果你想为这个工作被初始化.


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

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) { }
}
Run Code Online (Sandbox Code Playgroud)

可以看出输出如下.

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

  • @MrDoctorProfessorTyler,类按程序执行中遇到依赖关系的顺序初始化,包括类初始化.它从您的主类开始.如果此类具有引用类A的代码,则A将开始初始化.如果这又引用了B类,那么B的初始化将开始.如果B引用A,A中的代码可以在A完全初始化**之前运行**.这个问题是由于在静态初始化中尝试做太多工作而引起的. (2认同)
  • @MrDoctorProfessorTyler我已经更新了我的帖子,以包含一个相关的简单示例来说明问题. (2认同)