我正在尝试使用此单例,但是getInstance显然可以返回null:
class Singleton {
public static final String K_LEVEL = "level";
static Singleton instance = new Singleton();
private int level;
static Singleton getInstance() {
return instance;
}
int getLevel() {
return level;
}
void incrementLevel() {
System.out.println("LEVEL INCREASED TO " + ++level);
}
void addToLevel(int x) {
for(int i=0;i<x;i++)
incrementLevel();
}
}
class A {
public static void main(String[] args) {
Singleton s = Singleton.getInstance();
Integer i = Integer.getInteger(Singleton.K_LEVEL);
s.addToLevel(i);
}
}
我听说用Java实现单例非常困难,并且容易出现竞争状况。我的单例模式实现错误吗?最近,我将代码更改为如下所示,现在getInstance有时返回null。为什么?
$ java A -Dlevel=1
Exception in thread "main" java.lang.NullPointerException
at A.main(A.java:29)
您的Singleton没有错。没有并发问题,因为这不是多线程代码。
您以为s
为空,但实际上i
为空。
由于addToLevel
将int
作为参数,所以Integer i
被自动拆箱(从Integer
隐式转换为int
),但是由于i
为null
,因此抛出了NullPointerException
。当要掩盖的值为NullPointerException
时,自动拆箱操作将引发null
。
Integer.getInteger(Singleton.K_LEVEL)
返回null
的原因是因为您做了java A -Dlevel=1
,而不是java -Dlevel=1 A
。后者是正确的语法。
这与您的单例模式无关,这对我来说很好。 Integer.getInteger(Singleton.K_LEVEL);
方法返回null。我敢打赌"level"
系统属性尚未设置且为null
。
java A -Dlevel=1
您需要在命令行上放置-Dlevel=1
之前 A
类。如果您调试代码或打印出系统属性,则会看到它为null。
java -Dlevel=1 A
[当您尝试将null
传递到addToLevel(int x)
并尝试将null
自动拆箱为int x
时会得到NPE。
此外,如果该类被多个线程使用,则应考虑在可重入的AtomicInteger
类内部使用Singleton
。
[static Singleton instance = new Singleton();
应该是最终版本,以防止出现竞争状况。