最近工作中遇到过使用饿汉式单例导致的空指针异常,特此记录,加深印象。
问题复现
简化代码如下:
public class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {return instance;}
private static final Properties config = System.getProperties();
private String name = config.getProperty("name");
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args)
{
System.out.println(Singleton.getInstance().getName());
}
}
咋一看貌似没什么问题,运行发现抛出异常:
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.NullPointerException
原因分析
究其原因是类和类的实例的初始化顺序问题,一般情况下类的实例创建是在类初始化完成之后,所以类中定义的静态变量和常量的初始化后的值在类对象中肯定是能够访问到值的(即例子中的config),但是上面的例子中,在类的初始化过程中实例化了单例对象,所以单例对象的构造在类初始化完成之前,由于类的静态元素初始化顺序是代码定义的顺序,所以此时类的静态变量config还没有初始化,是默认值null,在构造方法中就抛空指针异常了。
修改方法
1.可以使用其他方式的单例模式,如懒汉式,或者使用静态内部类的饿汉式。
避免单例对象的构造在类初始化完成前触发。
2.将单例对象的创建放在所有静态变量、静态代码块最后。避免引用到未初始化的静态变量。
3.将name改成静态变量,这样会在config后再初始化。
网友评论