我有这样的代码:
class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
System.out.println("Singleton constructed.");
}
public static Singleton getInstance() {
return INSTANCE;
}
}
当我们没有getInstance的任何其他静态方法时,这个单例是否已初始化?据我所知,只有在某些情况下才会初始化类,例如:
因此,当唯一的静态方法是getInstance
且构造函数是私有的时,除了使用getInstance方法(除了反射)之外,不可能以任何其他方式初始化Singleton类。所以只有在我们需要时才创建对象,所以它是一个懒惰的初始化,对吧?或许我错过了什么?
答案 0 :(得分:2)
它立即被初始化,所以不,它不是。通常,延迟初始化意味着您在尝试实际检索它时初始化它,但该字段尚未初始化。
延迟初始化不是关于类初始化 - 它关于包含在其中的字段。在您的情况下,只要加载类,该字段将立即初始化。
您的示例适合使用延迟初始化:
class Singleton {
private static Singleton INSTANCE;
private Singleton() {
System.out.println("Singleton constructed.");
}
public static Singleton getInstance() {
if(INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
这只会在实际请求时构造单例,而不仅仅是在内存中加载Singleton
类时。在你的情况下,如果它被加载到内存中,那么它的static
字段将被初始化(包括你的单例字段)。
答案 1 :(得分:1)
System.out.println(Singleton.class);
只要创建实例,引用静态成员或通过编程方式加载类,类加载器就会加载类:
Class<?> clazz = Class.forName("Singleton"); // fully qualified classname
上述语句导致加载类,并且将按照类中的外观顺序处理所有静态成员和块。在您的示例类中,这将导致INSTANCE变量被初始化(以及要打印到System.out的消息)。这证明您的方法不能保证延迟加载。
实现延迟加载单例的更好方法是使用Singleton holder模式:
class Singleton {
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {
// hide constructor
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
答案 2 :(得分:1)
您提到了静态方法和私有构造函数。添加另一个静态字段,如:
static int NUMBER = 13;
单词类中的。而在其他类的主要方法中:
System.out.println(Singleton.NUMBER);
然后,你会看到你的Singleton没有延迟初始化。
但是,当你的领域是静态时最终:
static final int NUMBER = 13;
Singleton是懒惰的初始化。
此外,当您在Singleton类中添加静态和非静态初始化块时:
{
System.out.println("non-static");
}
static {
System.out.println("static");
}
顺序是:非静态,私有构造函数然后是静态的,因为您将对象实例化为静态字段的值。所以,这非常棘手:)
总之,在某些情况下,您的Singleton可能被视为延迟初始化,但通常不是。
答案 3 :(得分:0)
不,它不是懒惰的初始化。 懒惰意味着第一次打电话或从不。在你的情况下,它不是第一次打电话。
您可以将延迟初始化问题传递给SingletonHolder
类。它将在首次getInstance
来电时初始化。
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
答案 4 :(得分:0)
如果您使用的是.NET 4(或更高版本),John Skeet建议您执行以下操作:
您可以使用System.Lazy类型使懒惰变得非常简单。您所需要做的就是将一个委托传递给构造函数,该构造函数将调用Singleton构造函数-使用lambda表达式最容易做到。
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy = new Lazy<Singleton> (() => new
Singleton());
public static Singleton Instance { get { return lazy.Value; } }
private Singleton()
{
}
}
很简单,表现也不错。如果需要,还可以使用 IsValueCreated 属性检查是否已创建实例。
上面的代码隐式地使用 LazyThreadSafetyMode.ExecutionAndPublication 作为Lazy的线程安全模式。根据您的要求,您可能希望尝试其他模式。