有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Bill Pugh Singleton为什么使用容器?

我有以下代码:

package DesignPatterns;

public class SingletonProblem
{
    public static void main(String[] args) {
        System.out.println(BillPughSingleton.getInstance());
        System.out.println(BillPughSingletonWithoutContainer.getInstance());
    }
}

class BillPughSingletonWithoutContainer
{
    private static BillPughSingletonWithoutContainer instance = new BillPughSingletonWithoutContainer();

    static {
        System.out.println("Static is now loaded in BillPughSingletonWithoutContainer");
    }

    private BillPughSingletonWithoutContainer() {}

    public static BillPughSingletonWithoutContainer getInstance()
    {
        return instance;
    }
}

class BillPughSingleton
{
    private static class Container
    {
        public static BillPughSingleton instance = new BillPughSingleton();
    }

    private BillPughSingleton() {}

    public static BillPughSingleton getInstance()
    {
        return Container.instance;
    }
}

输出为:

DesignPatterns.BillPughSingleton@36baf30c
Static is now loaded in BillPughSingletonWithoutContainer
DesignPatterns.BillPughSingletonWithoutContainer@5ca881b5

如果在没有容器的示例中,在调用BillPughSingletonWithoutContainer.getInstance()时实例似乎也是延迟加载的,那么容器为什么有用呢

在急切地加载(BillpughSingleton Without容器被称为什么)中,我期望输出是:

Static is now loaded in BillPughSingletonWithoutContainer
DesignPatterns.BillPughSingleton@36baf30c
DesignPatterns.BillPughSingletonWithoutContainer@5ca881b5

而不是:

DesignPatterns.BillPughSingleton@36baf30c
Static is now loaded in BillPughSingletonWithoutContainer
DesignPatterns.BillPughSingletonWithoutContainer@5ca881b5

换句话说,使用容器的好处是什么(在Java中)


共 (2) 个答案

  1. # 1 楼答案

    这组类显示了定义单例的三种常见方法—两种方法与您定义的方法类似,另一种方法使用enum。每个帮助中的System.out.println()都可以发现初始化中的差异:

    enum SingletonEnum {
        INSTANCE;
    
        public static void hello() { System.out.println("hello() SingletonEnum"); }
    
        public static SingletonEnum getInstance() {
            System.out.println("SingletonEnum getInstance "+INSTANCE);
            return INSTANCE;
        }
    
        static {
            System.out.println("SingletonEnum static");
        }
    
        {
            System.out.println("SingletonEnum instance "+this);
        }
    }
    class SingletonClass {
        public static final SingletonClass INSTANCE = new SingletonClass();
    
        public static void hello() { System.out.println("hello() SingletonClass"); }
    
        public static SingletonClass getInstance() {
            System.out.println("SingletonClass getInstance "+INSTANCE);
            return INSTANCE;
        }
    
        static {
            System.out.println("SingletonClass static");
        }
    
        {
            System.out.println("SingletonClass instance "+this);
        }
    }
    class SingletonContainer
    {
        private static class Container {
            public static SingletonContainer instance = new SingletonContainer();
        }
        public static void hello() { System.out.println("hello() SingletonContainer"); }
    
        public static SingletonContainer getInstance()
        {
            System.out.println("SingletonContainer getInstance "+Container.instance);
            return Container.instance;
        }
    
        static {
            System.out.println("SingletonContainer static");
        }
    
        {
            System.out.println("SingletonContainer instance "+this);
        }
    }
    

    BillPughSingleton的主要好处是,实例化只在调用getInstance()时发生,而对于其他方法,第一个方法访问hello()会导致实例初始化。enum版本是一个更简单的声明,可以确保只有一个实例(其他实例需要私有构造函数,在我的示例中省略)

    public static void main(String[] args) {
        System.out.println("1");
        SingletonClass.hello();
        System.out.println("2");
        SingletonContainer.hello();
        System.out.println("3");
        SingletonEnum.hello();
    
        System.out.println("4");
        SingletonClass.getInstance();
        System.out.println("5");
        SingletonEnum.getInstance();
        System.out.println("6");
        SingletonContainer.getInstance();
        System.out.println("7");
    }
    

    这会打印类似这样的内容,因此容器版本的构造将推迟到其getInstance调用:

    1
    SingletonClass instance SingletonClass@5acf9800
    SingletonClass static
    hello() SingletonClass
    2
    SingletonContainer static
    hello() SingletonContainer
    3
    SingletonEnum instance INSTANCE
    SingletonEnum static
    hello() SingletonEnum
    4
    SingletonClass getInstance SingletonClass@5acf9800
    5
    SingletonEnum getInstance INSTANCE
    6
    SingletonContainer instance SingletonContainer@5ca881b5
    SingletonContainer getInstance SingletonContainer@5ca881b5
    7
    
  2. # 2 楼答案

    BillPughSingletonWithoutContainer中,static {}初始化器块总是在类第一次被引用时执行(这基本上来自代码的imports)。这里不存在惰性初始化技巧。根据docs,正确使用静态初始化器是。。。初始化静态字段

    这与静态内部类不同,后者仅在第一次引用类时加载-这仅发生在BillPughSingleton的构造函数中(当它被调用时,而不是在加载时)https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom