Java 是否已初始化此singleton lazy?

Java 是否已初始化此singleton lazy?,java,singleton,lazy-initialization,Java,Singleton,Lazy Initialization,我有这样的代码: class Singleton { private static final Singleton INSTANCE = new Singleton(); private Singleton() { System.out.println("Singleton constructed."); } public static Singleton getInstance() { return INSTANCE;

我有这样的代码:

class Singleton {

    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {
        System.out.println("Singleton constructed.");
    }

    public static Singleton getInstance() {
        return INSTANCE;
    }

}
当我们没有任何其他getInstance静态方法时,这个单例惰性初始化了吗?据我所知,类仅在某些情况下初始化,例如:

类的实例是使用new关键字或 使用class.forName的反射,可能会引发 Java中的ClassNotFoundException。 调用类的静态方法。 已指定类的静态字段。 使用类的静态字段,该字段不是常量变量。 若类是顶级类,则执行词汇嵌套在类中的assert语句。 调查:


所以,当唯一的静态方法是getInstance并且构造函数是私有的时,除了使用反射之外,不可能以任何其他方式初始化Singleton类。所以这个对象只在我们需要的时候创建,所以它是一个延迟初始化,对吗?或者我遗漏了什么?

它被立即初始化,所以不,不是。通常,延迟初始化意味着您在尝试实际检索时对其进行初始化,但字段尚未初始化

延迟初始化与类的初始化无关,它与类中包含的字段有关。在您的情况下,一旦类被加载,字段将立即初始化

您的示例适合使用惰性初始化:

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,而不仅仅是在内存中加载singleton类时。在您的情况下,如果它被加载到内存中,那么它的静态字段将被初始化,包括您的单例字段。

它被立即初始化,所以不,它不是。通常,延迟初始化意味着您在尝试实际检索时对其进行初始化,但字段尚未初始化

延迟初始化与类的初始化无关,它与类中包含的字段有关。在您的情况下,一旦类被加载,字段将立即初始化

您的示例适合使用惰性初始化:

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,而不仅仅是在内存中加载singleton类时。在您的情况下,如果它加载到内存中,那么它的静态字段将被初始化,包括您的单例字段。

编辑:我错了。类不是通过引用来加载的,如下所示:

System.out.println(Singleton.class); 
创建实例、引用静态成员或以编程方式加载时,类加载器会立即加载类:

Class<?> clazz = Class.forName("Singleton"); // fully qualified classname

编辑:我错了。类不是通过引用来加载的,如下所示:

System.out.println(Singleton.class); 
创建实例、引用静态成员或以编程方式加载时,类加载器会立即加载类:

Class<?> clazz = Class.forName("Singleton"); // fully qualified classname

不,它不是懒惰的。
懒惰是指第一次打电话或从不打电话。在你的情况下,它不是第一次呼叫

您可以将延迟初始化问题传递给SingletonHolder类。它将在第一次getInstance调用时初始化


不,它不是懒惰的。
懒惰是指第一次打电话或从不打电话。在你的情况下,它不是第一次呼叫

您可以将延迟初始化问题传递给SingletonHolder类。它将在第一次getInstance调用时初始化


您提到了静态方法和私有构造函数。添加另一个静态字段,如:

static int NUMBER = 13;
在你的单身班。在其他类别的主要方法中:

System.out.println(Singleton.NUMBER);
然后,您将看到您的单例不是惰性初始化的

但是,当您的字段是静态最终字段时:

static final int NUMBER = 13;
单例是惰性初始化的

此外,在Singleton类中添加静态和非静态初始化块时:

{
    System.out.println("non-static");
}

static {
    System.out.println("static");
}
顺序是:非静态,私有构造函数,然后是静态的,因为您正在将一个对象作为静态字段的值进行设置。因此,这是非常棘手的:


总之,在某些情况下,您的单例可能被认为是延迟初始化的,但它不是一般的。

您提到了静态方法和私有构造函数。添加另一个静态字段,如:

static int NUMBER = 13;
在你的单身班。在其他类别的主要方法中:

System.out.println(Singleton.NUMBER);
然后,您将看到您的单例不是惰性初始化的

但是,当您的字段是静态最终字段时:

static final int NUMBER = 13;
单例是惰性初始化的

此外,在Singleton类中添加静态和非静态初始化块时:

{
    System.out.println("non-static");
}

static {
    System.out.println("static");
}
顺序是:非静态,私有构造函数,然后是静态的,因为您正在将一个对象作为静态字段的值进行设置。因此,这是非常棘手的:


总之,在某些情况下,您的Singleton可能被认为是惰性初始化的,但通常不是这样。

如果您使用的是.NET 4或更高版本,John Skeet建议您执行以下操作:

您可以使用System.Lazy类型使惰性变得非常简单。您所需要做的就是将一个委托传递给调用单例构造函数的构造函数——这是使用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作为延迟线程的线程安全模式。根据您的要求,您可能希望尝试其他模式。

如果您使用的是.NET 4或更高版本,John Skeet建议您执行以下操作:

您可以使用System.Lazy类型使惰性变得非常简单。您所需要做的就是将一个委托传递给调用单例构造函数的构造函数——这是使用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作为延迟线程的线程安全模式。根据您的要求,您可能希望尝试其他模式。

是。但是什么时候加载类呢?不仅仅是当我们使用getInstance方法时?@tdudzik No。例如,如果其他类有接受Singleton作为参数或返回它的方法,或者类有Singleton类型的字段,那么它将被加载。您能给我一个示例,当我们看到Singleton构造时,不使用Singleton.getInstance方法吗?因为我不完全明白。当我使用Singleton类型作为参数时,实际上加载了Singleton类,但仍然没有调用构造函数。是。但是什么时候加载类呢?不仅仅是当我们使用getInstance方法时?@tdudzik No。例如,如果其他类有接受Singleton作为参数或返回它的方法,或者类有Singleton类型的字段,那么它将被加载。您能给我一个示例,当我们看到Singleton构造时,不使用Singleton.getInstance方法吗?因为我不完全明白。当我使用Singleton类型作为参数时,实际上加载了Singleton类,但仍然没有调用构造函数;它不是打印Singleton构造的。?那么为什么我在编写System.out.printlnSingleton.class时;它不是打印单例构造的。但是你如何证明它不是惰性初始化的呢?惰性是指第一次调用或从不。在您的情况下,它不是第一次调用,但您如何证明它不是懒惰初始化的?懒惰是指第一次调用或从不。在你的情况下,它不是第一次呼叫