为什么私有静态字段=新的Singleton在Java中不是懒惰的?
我阅读了很多关于Singleton的文章,其中大多数作者都说Java中的Singleton变种:
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } }
不是懒惰 ( EAGER然后 )。
但是我无法理解为什么, Singleton()
构造函数只会在Singleton
类初始化时被调用。 我知道几个可以触发类初始化的原因:
- 使用
new
with constructor(但在这种情况下构造函数是私有的)。 - 访问或设置静态字段(此处为私有)。
- 使用静态方法。
- 使用reflection:
Class.forName("Singleton")
。
所以这里我们的对象只会在使用静态方法getInstance()
(我仍然是LAZY初始化)和reflection时创建(但是reflection可能会破坏很多Singleton变体,除了enum
之外)。
也许我看不到明显的东西,请解释一下,我哪里错了?
基本上这是一个懒惰程度的问题。 它是懒惰的,因为它不会在类初始化之前构造单例,但是它很渴望可能存在你想要使用类而不初始化单例本身的情况。
例如:
public final class Singleton { private static final Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } public static void sayHello() { System.out.println("Hello!"); } }
调用Singleton.sayHello()
将实例化单例,即使我们不希望它……所以它不像它那样懒惰。
你可以使用嵌套类型来解决这个问题:
public final class Singleton { private Singleton() {} public static Singleton getInstance() { return Holder.instance; } public static void sayHello() { System.out.println("Hello!"); } private static class Holder { private static final Singleton instance = new Singleton(); } }
现在, Singleton.Holder
只能使用getInstance
方法进行初始化。 它是懒惰和线程安全的,没有锁定。
根据我的经验,通常单例类的唯一静态方法是getInstance
方法,在这种情况下它们是等效的(例如,假设您不使用reflection以某种方式初始化类型)。
它不是懒惰的,因为一旦加载了类就会创建singeton对象。
懒惰的Singleton会在首次使用时创建对象。