• ExceptionInInitializerError


    代码如下:

    public class Main {
    
        public static void main(String[] args) throws Exception {
            Foo foo = Foo.getInstance();
        }
    
    }
    
    class Foo {
    
        private static Foo instance = new Foo();
        private static List<String> list = new ArrayList<>();
    
        public static Foo getInstance() {
            return instance;
        }
    
        public Foo() {
            list.add("Hello");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    运行时异常如下:

    Exception in thread "main" java.lang.ExceptionInInitializerError
    	at com.company.Main.main(Main.java:11)
    Caused by: java.lang.NullPointerException
    	at com.company.Foo.<init>(Main.java:26)
    	at com.company.Foo.<clinit>(Main.java:18)
    	... 1 more
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    通过异常可知是这行代码出了空指针异常:list.add("Hello");,很明显,list对象为空,我这个代码已经是简化之后的,在真实项目中代码很多的时候是有点懵人,list是一个静态变量,而Foo()函数是一个实例函数,一般理解就是静态变量先初始化的啊,为什么会是空啊!没错,静态变量先初始化,但是这里Foo实例也是在静态变量中直接初始化的:private static Foo instance = new Foo();,所以这行代码先执行了,先要初始化instance这个静态变量,而你在初始化这个变量的时候又用到了另一个静态变量list,而这个静态变量声明是在后面的,所以还没初始化到,所以就为null了,解决方案有两种:

    方式一:把list声明在instance的前面,如下:

    class Foo {
        public static List<String> list = new ArrayList<>();
        private static Foo instance = new Foo();
    }
    
    • 1
    • 2
    • 3
    • 4

    这样我们在调用 Foo.getInstance()的时候,它就加载了Foo的Class到内存中,一加载Class就会初始化静态变量,多个静态变量是按声明的先后顺序声明的,所以list先声明就会先初始化,然后在初始化instance,此时的list就不为空了。

    方式二:不修改list的声明位置也没关系,但是需要把liststatic修饰符去除掉,如下:

    class Foo {
        private static Foo instance = new Foo();
        public List<String> list = new ArrayList<>();
    }
    
    • 1
    • 2
    • 3
    • 4

    Foo的字节码一加载进内存就会初始化静态变量instance,而instancenew了一个Foo()对象,所以此时会初始化Foo上面的成员变量list(非静态成员变量),所有的成员变量都初始化完成之后,再会执行Foo()构造函数中的代码,所以此时list也不会为空了。

  • 相关阅读:
    [CISCN2019 华北赛区 Day1 Web2]ikun
    Java数组的一些小知识点
    C语言- 数据转换汇总
    电信保温杯笔记——《统计学习方法(第二版)——李航》第19章 马尔可夫链蒙特卡罗法
    DeepExploit——基于强化学习的自动渗透工具
    在linux服务器用git命令对比master和release分支变化,把改动的文件类名存入到一个文件里用java怎么实现
    设计模式笔记1
    Maven 插件统一修改聚合工程项目版本号
    恢复Windows 11经典右键菜单:一条命令解决显示更多选项问题
    C语言 力扣习题 10.19日 day1
  • 原文地址:https://blog.csdn.net/android_cai_niao/article/details/126224765