好的,我们一步步拆开来说 Java 中的 ExceptionInInitializerError,让你不仅知道怎么解决,还能明白它为什么会出现。


1. 它是什么

ExceptionInInitializerError 表示类的初始化阶段发生了异常,常见于:

  • 静态变量初始化出错
  • 静态代码块出错

初始化失败时,JVM 会抛出这个包装异常,把真正的根本原因(Cause)包在里面。


2. 常见触发场景

场景 1:静态变量赋值出错

public class Demo {
    static int num = 1 / 0; // 除零异常

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

运行:

Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.ArithmeticException: / by zero

这里真正的错误是 ArithmeticException,但它发生在类初始化阶段,所以外面套了 ExceptionInInitializerError


场景 2:静态代码块出错

public class Demo {
    static {
        String str = null;
        str.length(); // NullPointerException
    }

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

场景 3:引用的类初始化失败

class A {
    static int x = 1 / 0; // 初始化失败
}

public class Demo {
    static A a = new A(); // 这里触发 A 类初始化

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

如果一个类的静态初始化失败,那么以后再用这个类时,都会抛出 NoClassDefFoundError,而不是重新初始化。


3. 解决步骤

  1. 查看 Caused by
    • 在异常堆栈中找到 根本原因Caused by: 后面的部分)
  2. 定位静态变量 / 静态代码块
    • 找出是在类初始化阶段执行的逻辑
  3. 避免复杂初始化
    • 不要在静态变量或静态代码块里做复杂计算或可能抛异常的操作
  4. 延迟初始化(Lazy Initialization)
    • 用构造方法、懒加载(if 判断)或单例模式在需要时再初始化
  5. 做好异常捕获
    • 如果必须在静态代码块中写逻辑,可以 try-catch 防御
    static { try { riskyOperation(); } catch (Exception e) { e.printStackTrace(); } }

4. 防御性示例

public class Config {
    static Properties props;

    static {
        try {
            props = new Properties();
            props.load(new FileInputStream("config.properties"));
        } catch (IOException e) {
            // 打印错误并提供默认值,避免初始化失败
            e.printStackTrace();
            props.setProperty("defaultKey", "defaultValue");
        }
    }
}

核心记忆点
ExceptionInInitializerError 是“初始化时异常的外壳”,先看里面的 Caused by 才能真正定位问题