所以我知道单例模式是这样实现的:
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() {}
}
减少代码行数并且似乎完全相同。当然,减去延迟初始化,但我不明白为什么懒惰初始化无论如何都会是一个重要的好处。我不是很有经验,如果你能用你的知识启发我,我将不胜感激,谢谢。
答案 0 :(得分:4)
初始化单例实例内联并让类加载器担心同步可能不是一种非常常见的做法,但它绝对不是闻所未闻的。
然而,常见的习惯用法是将实例变量设为私有并通过getter返回它,这样其他代码就不会直接依赖它。这样,如果将来你决定想要更高级的东西(例如,你提到的延迟初始化),你可以轻松地重构你的代码而不破坏API:
A*.jar
答案 1 :(得分:2)
您的第一个代码使用synchronized
关键字进行延迟创建。 instance = new ClassName()
这些代码的问题是instance
var在构造单例之前可能变为非null,并且可以在伪代码中解释,JRE用于创建实例:
mem = allocate() ;
instance = mem ;
ctorSingleton(instance)
因此,如果多个线程同时访问方法getInstance,是否有可能获得一个新实例,因为在java中你有2条指令和JRE解释的伪代码在3中执行。
我认为你的第二个工具是好的,因为你确信它能正常工作,并且线程或同步问题很难解决。
这来自法国文章: http://christophej.developpez.com/tutoriel/java/singleton/multithread/
答案 2 :(得分:1)
这是我一直问单身爱好者的问题,到目前为止,我还没有听到满意的答案。人们说全球变量很糟糕' (我来自C ++世界,所以措辞是C ++特定的,但想法是一样的)。当我问他们所爱的辛格尔顿究竟与全球有什么不同时,我听到的只是闷闷不乐的火腿。我个人发现Singleton只有一个好处 - 延迟初始化,这使得控制实例化的顺序成为可能。如果不需要,则不需要Singleton。
答案 3 :(得分:0)
优点来自于单例的编写者可以更新getter(getInstance)以获得更复杂的规则而不会导致单例的用户必须重新编译他们的代码。这就是Mureinik所说的:"这样,如果将来你决定想要更高级的东西(例如,你提到的延迟初始化),你就可以轻松地重构你的代码而不会破坏API"