java static init,Java静态变量以及非标准单态模式的坑

今天遇到一个很诡异的bug,调试了半天也没有看出来有什么问题,抽象一下代码如下:

public class Instance

{

public static Instanceinstance= new Instance();

public static Mapmap= new HashMap();

public static Instance instance()

{

return Instance.instance;

}

public static void main(String[] args)

{

Instance.instance().test();

}

public Instance()

{

Instance.map.put("abc", "def");

}

public void test()

{

System.out.println("test called");

}

}

结果一运行就出下面的错误,

java.lang.ExceptionInInitializerError

Caused by: java.lang.NullPointerException

at edu.bupt.test.Instance.(Instance.java:27)

at edu.bupt.test.Instance.(Instance.java:9)

Exception in thread "main"

当时没有太注意这个Exception,因为还有另外一个NullException

后来仔细看了一下堆栈才发现,这是在初始化的过程中出的问题,

首先我们来回忆一下类的加载过程

1、加载类文件

2、初载父类

3、初始化静态变量和static代码块

4、调用构造函数

好了,问题就出在第3步了,因为这里我们用了一个非标准的单态模式,

直接把静态变量在static里初始化了。由于第三步的初始化步骤是根据你

的变量的定义顺序来初始化的,于是杯具产生了:

首先,你要初始化static Instance instance,这样你就要调用Instance

的构造函数,这个时候,构造函数里要访问map变量,而这个static变量

还没有初始化呢,于是空指针就出现了。

结论:要仔细阅读栈的话,这个问题还是很容易定位的,这么看init代表构造函数

而cinit代表静态初始化函数,因此这个过程其实是在静态初始化调用构造函数时

发生的,去看一个构造函数分析一下就得到结果了。

另外尽可能避免地使用在变量定义时就初始化变量,这样会导致一些问题的追查

比较麻烦,比如这个问题就是一个很典型的例子,解决问题的办法居然是要将两个

变量定义顺序调整一下,如果使用了一些代码format工具,比如eclipse的format功能,

这种诡异的bug就会出现了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值