1

我在一次采访中被问到这个问题。我有一个基类(比如 class A),然后是两个子类BC. 现在我无法控制 B 和 C 的构造函数(那些构造函数不能是 private ,必须是 public )但要求是 and 的每个实例都B应该C单例。我怎样才能做到这一点?

4

2 回答 2

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);
        }
    }
}

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


我会说这是一个相当难的面试问题......


@emory 评论:

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

这里的问题(如果算作问题的话)是 B1 和 B2 实例也是 B 实例,这意味着 B 实例不再是单例……取决于您希望实现的单例的定义。

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

  • 您可以反思性地测试子类修饰符,看看这些类是否是最终类,并拒绝创建非最终类的实例......以防万一。

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

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

于 2012-08-14T06:17:14.237 回答
0

我正在为 B 级展示它

尽管您可以使用Double checked locking, 并synchronized on method做到这一点..我向您展示了一种快速而肮脏的方法...

public class B {

    private static B b = new B();

    private B() {}

    public static B getInstance() {
           return b;
    }
}
于 2012-08-14T05:46:40.387 回答