7

我有这个我正在尝试使用的单例,但 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)
4

4 回答 4

3

您的单身人士没有任何问题。不存在并发问题,因为这不是多线程代码。

你以为s是空的,但实际上i那是空的。

由于addToLevel将 aint作为参数,因此被自动拆箱(从toInteger i隐式转换),但由于is ,被抛出。当被转换的值为.IntegerintinullNullPointerExceptionNullPointerExceptionnull

Integer.getInteger(Singleton.K_LEVEL)返回的原因null是因为你做java A -Dlevel=1了而不是java -Dlevel=1 A. 后者是正确的语法。

于 2013-03-27T19:23:54.717 回答
3

这与您的单例模式无关,这对我来说看起来不错。它Integer.getInteger(Singleton.K_LEVEL);是返回 null 的方法。我敢打赌"level"系统属性尚未设置并且是null.

java A -Dlevel=1

您需要在命令行上的类-Dlevel=1 之前放置。A如果您调试代码或打印出系统属性,您将看到它为空。

java -Dlevel=1 A

当您尝试将 in 传递nulladdToLevel(int x)尝试将 to 自动拆箱时,您null会得到一个 NPE int x

顺便说一句,如果这个类被多个线程使用,你应该考虑AtomicInteger在你的Singleton类内部使用可重入的。

于 2013-03-26T21:39:57.033 回答
2

java -Dlevel=1 A应该适合您的需求。

doc中,语法是java [ options ] class [ argument ... ], 并且-Dlevel=1被视为一个选项(请参阅选项部分)。

于 2013-03-26T22:08:57.017 回答
1

static Singleton instance = new Singleton();应该是最终的以防止竞争条件。

于 2013-03-27T17:34:46.220 回答