实现单例设计模式的标准方法是:
public class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
private Singleton() {}
}
我想知道你是否也可以像这样实现它:
public class Singleton {
private Singleton() {}
public final static Singleton INSTANCE = new Singleton();
}
如果是哪个版本更好?
答案 0 :(得分:10)
都不是。在这两种情况下,受信任的使用者都可以通过反射调用私有构造函数。另一个问题是,这些实现不能很好地与序列化一起使用,除非你采取额外的步骤来实现它(默认情况下,如果采用天真的方法,每次Singleton
反序列化,它将创建一个新实例)。
正确的解决方案是使用定义单个值的enum
。
public enum Singleton {
INSTANCE;
// methods
}
来自Effective Java:
虽然这种方法尚未被广泛采用,但单元素枚举类型是实现单例的最佳方法。
答案 1 :(得分:1)
为什么不使用枚举来实现Singleton?
public enum SingletonEnum {
Instance;
private static String testStr = "";
public static void setTestStr(String newTestStr) {
testStr = newTestStr;
}
public static String getTestStr() {
return testStr;
}
public static String sayHello(String name) {
return "Hello " + name;
}
}
答案 2 :(得分:0)
在我看来,第一个更好,因为它看起来更符合面向对象的方法。
答案 3 :(得分:0)
虽然这两种解决方案都没有什么特别的错误,但Wikipedia的这个解决方案应该为您提供最佳的兼容性,并为您提供一个线程安全的单例:
马里兰大学计算机科学研究员Bill Pugh撰写了关于使用Java实现Singleton模式的代码问题。[11] Pugh对“双重检查锁定”习惯的努力导致了Java 5中Java内存模型的变化,以及通常被认为是在Java中实现Singletons的标准方法。被称为初始化按需持有者习惯用法的技术尽可能地懒惰,并且适用于所有已知版本的Java。它利用了有关类初始化的语言保证,因此可以在所有兼容Java的编译器和虚拟机中正常工作。 嵌套类不会在调用getInstance()的时刻之前引用(因此不会由类加载器加载)。因此,该解决方案是线程安全的,无需特殊的语言结构(即易失性或同步)。
public class Singleton {
// Private constructor prevents instantiation from other classes
private Singleton() { }
/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder {
public static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}