如何创建派生类的单例?

Gee*_*eek 1 java singleton

我在接受采访时被问到这个问题.我有一个基类(类说A),然后两个子类BC.现在,我有超过B和C的构造函数没有控制(那些构造函数不能是私有的,必须是公开的),但要求是每一个实例B,并C应该是一个单身.我怎样才能做到这一点?

Ste*_*n C 6

我想我会在构造函数中执行此操作A.让它来调用this.getClass(),并使用它在私有HashSet中进行查找.如果你得到一个命中,那么之前已经创建了一个类的实例,并且你抛出一个异常.

public abstract class A {
    private static HashSet<Class<?>> classes = new HashSet<Class<?>>();

    public A () {
        synchronized (classes) {
            Class<?> c = this.getClass();
            if (classes.contains(c)) {
                throw NotSingletonException("Class " + c + " is not singleton");
            }
            classes.add(c);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你安排所有A的构造函数都这样做,那么子类就无法避免检查.并且由于JLS不允许你在一个this()super()调用周围放置一个try/catch ,一旦抛出异常,子类的构造函数就不能正常返回.


我会说这是一个非常难的面试问题......


@emory评论:

如果B和C不是最终的怎么办?然后我可以创建类B1,B2,C1,C2等.

这里的问题(如果它算作一个问题)是B1和B2实例也是B实例,这意味着B实例不再是单例...取决于你想要实现的单例的定义.

我可以看到几种处理方式:

  • 您可以反思地测试子类修饰符,看看类是否为final,并拒绝创建非final类的实例...以防万一.

  • 你可以HashSet<Class>用a 代替List<Class>.然后每次A调用构造函数时,它都会遍历调用elem.isAssignableFrom(c)每个元素类的列表.如果任何调用返回true,则违反(strict)单例不变量,因此应抛出异常.

可能需要根据您试图强制执行的单例模型来调整逻辑,但通用解决方案适用:记录类并检查/比较新类与以前的类.