Java 单例与公共静态最终变量

Java 单例与公共静态最终变量,java,singleton,Java,Singleton,所以我知道singleton模式是这样实现的: public class ClassName { private static ClassName instance; public static ClassName getInstance() { if (instance == null) { instance = new ClassName(); } return instance; }

所以我知道singleton模式是这样实现的:

public class ClassName {
    private static ClassName instance;

    public static ClassName getInstance() {
        if (instance == null) {
            instance = new ClassName();
        }
        return instance;
    }

    private ClassName() {}
}
public class ClassName {
    public static final ClassName instance = new ClassName();
    private ClassName() {}
}
我想问的是为什么你不能这样做:

public class ClassName {
    private static ClassName instance;

    public static ClassName getInstance() {
        if (instance == null) {
            instance = new ClassName();
        }
        return instance;
    }

    private ClassName() {}
}
public class ClassName {
    public static final ClassName instance = new ClassName();
    private ClassName() {}
}

更少的代码行,似乎做了完全相同的事情。当然要减去延迟初始化,但是我不明白为什么延迟初始化会有很大的好处。我不是很有经验,如果您能用您的知识来启发我,我将不胜感激,谢谢。

内联初始化单例实例并让类加载器担心同步可能不是一种非常常见的做法,但这肯定不是闻所未闻的

然而,常见的习惯用法是让实例变量private并通过getter返回它,这样就没有其他代码直接依赖它。这样,如果将来您决定使用更高级的东西(例如,您提到的惰性初始化),您可以轻松地重构代码而不破坏API:

public class ClassName {
    private static final ClassName instance = new ClassName();

    public static ClassName getInstance() {
        return instance;
    }

    private ClassName() {}
}

这也是我经常问单身情侣的问题,到目前为止,我还没有听到一个令人满意的答案。人们说“全局变量是坏的”(我来自C++世界,所以措辞是C++特定的,但是想法是一样的。当我问他们钟爱的单身汉和全球单身汉到底有什么不同时,我只听到了含糊不清的hms。我个人发现单例初始化只有一个好处——延迟初始化,这使得控制实例化顺序成为可能。如果不需要,则不需要Singleton。

您的第一个代码使用带有
synchronized
关键字的惰性创建
instance=new ClassName()
这类代码的问题在于
instance
var在构造singleton之前可能变为非null,并且可以在伪代码中进行解释,JRE为创建实例所做的工作是:

mem = allocate() ;
instance = mem ;
ctorSingleton(instance)
因此,如果多个线程同时访问getInstance方法,是否有可能获得一个新实例,因为在java中,有2条指令和JRE解释的伪代码在3中完成

我认为你的第二个实现是好的,因为你确信它会很好地工作,线程或同步问题很难解决。 这是一篇来自法国的文章:


优点来自这样一个事实:单例编写器可以更新getter(getInstance),使其具有更复杂的规则,而无需单例用户重新编译其代码。这就是Mureinik所说的:“这样,如果将来你决定想要更高级的东西(比如,你提到的惰性初始化),你可以轻松地重构代码,而不破坏API”

我仍然不理解使用单例的好处。您可以始终在静态构造函数中初始化实例,如果它不是公共API,我们不需要担心它;我们可以在以后重构它,不需要懒惰。您的第二个解决方案很好。在java中,加载无论如何都是惰性的——类只在第一次使用时加载(更准确地说,初始化)。
getIntance()
是另一个抽象层;正如他们所说,每个问题的解决方案都更抽象:)