有 Java 编程相关的问题?

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

是否有理由在Java中的另一个类中保留对单例实例的引用?

这可能是一个相当愚蠢的问题,但今天早些时候,我遇到了一些代码,其中外部类存储对单例类实例的引用(在私有字段中),并使用此引用,而不是每次都从单例类获取实例

起初,我觉得它的设计很糟糕,因为它在类中添加了一个字段,但有没有其他原因不应该这样做(或者应该这样做)

小代码示例来说明:

enum SomeSingletonObject {
    INSTANCE;

    public void someMethod() {...}
}

class AnotherObject {
    private SomeSingletonObject sso;

    public AnotherObject() {
        this.sso = SomeSingletonObject.INSTANCE;
    }

    public void someMethod() {
        sso.someMethod();
        // instead of 
        // SomeSingletonObject.INSTANCE.someMethod();
    }
}

共 (4) 个答案

  1. # 1 楼答案

    如果您可以保证给定的单例确实是一个单例,那么这种方法将起作用。在更复杂的环境中,它可能会失败,例如:

    public class Singleton {
        private static Singleton instance = new Singleton();
    
        public static Singleton instance() {
    
            if (someCondition == true) {
                Singleton.instance.close() // close the object
                Singleton.instance = new Singleton();
            }
    
            return Singleton.instance;
        }
    }
    

    上面的示例并不是一个真正的单例,但它将破坏您提供的代码,因为新引用已分配给instance。如果使用外部库而不了解/访问它们的内部行为,则可能会出现这些问题

    我会避免“缓存”对singleton的引用

  2. # 2 楼答案

    想到的第一个原因是使它易于替换为其他对象,即实现公共接口或扩展公共超类的对象

    此外,如果由不同的类装入器装入,则可能存在两个单例实例

    此外,尽管不完全符合单例模式的精神,但它可以用于存储对单例对象的旧实例的引用

  3. # 3 楼答案

    在这个例子中,没有,没有好处

    但是,如果您使用依赖项注入,而您的类将其依赖项作为构造函数参数,那么传入一个单例实例可能非常有用,在这种情况下,您将别无选择,只能存储引用

  4. # 4 楼答案

    实际上,我在这方面似乎有些好处,因为如果您使用带有构造函数的枚举来管理静态引用,它将在启动时初始化(就像在类加载时一样),并且在启动后永远不会更改

    这可能有助于分离permgen类,这可能会改进容器的热部署,因为这是一个问题。但我不知道事实是否如此

    消极的一面是,如果枚举正在进行初始化,您可能会失去静态引用的生命周期管理

    更好的解决方案通常是避免这样的静态单例,并依赖依赖依赖注入或AOP(Google Spring的@Configurable)