我正在尝试使用这个单例,但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)
答案 0 :(得分:2)
这不是关于你的单身模式,这对我来说很好。正是Integer.getInteger(Singleton.K_LEVEL);
方法返回null。我敢打赌,"level"
系统属性尚未设置且为null
。
根据我的评论,您需要在命令行上将-Dlevel=1
放在 A
类之前。如果您调试代码或打印出系统属性,您将看到它是null。
当您尝试将null
传递到addToLevel(int x)
并尝试将null
自动取消装箱为int x
时,您会收到NPE。
顺便说一句,如果多个线程使用此类,则应考虑在AtomicInteger
类中使用可重入的Singleton
。
答案 1 :(得分:2)
java -Dlevel=1 A
应该符合您的需求。
从doc开始,语法为java [ options ] class [ argument ... ]
,-Dlevel=1
被视为一个选项(请参阅options部分)。
答案 2 :(得分:2)
你的单身人士没有任何问题。没有并发问题,因为这不是多线程代码。
您以为s
为空,但实际上i
为空。
由于addToLevel
将int
作为参数,Integer i
被自动装箱(从Integer
隐式转换为int
),但自{{1} } i
,null
被抛出。当被隐蔽的值为NullPointerException
时,Autounboxing会抛出NullPointerException
。
null
返回Integer.getInteger(Singleton.K_LEVEL)
的原因是因为您null
而不是java A -Dlevel=1
。后者是正确的语法。
答案 3 :(得分:0)
static Singleton instance = new Singleton();
应该是最终的,以防止竞争。