我在接受采访时被问到这个问题。我有一个基类(比如类A
),然后是两个子类B
和C
。现在我无法控制B和C的构造函数(那些构造函数不能是私有的,必须是公共的)但要求是B
和C
的每个实例都应该是单身人士。我怎样才能做到这一点?
答案 0 :(得分: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()
或super()
调用周围放置try / catch,所以一旦抛出异常,子类的构造函数就不能正常返回。
我会说这是一个非常难以面试的问题......
@emory评论:
如果B和C不是最终的怎么办?然后我可以创建B1,B2,C1,C2等类
这里的问题(如果它算作一个问题)是B1和B2实例也是B实例,这意味着B实例不再是单例...取决于你想要的单身人士的定义实施。
我可以看到几种解决方法:
你可以反思地测试子类修饰符,看看这些类是否为final,并拒绝创建非final类的实例......以防万一。
您可以将HashSet<Class>
替换为List<Class>
。然后每次调用A
构造函数时,它将迭代调用每个元素类的elem.isAssignableFrom(c)
列表。如果任何调用返回true,则违反(strict)单例不变量,因此应抛出异常。
逻辑可能需要根据您尝试强制执行的单身模型进行调整,但一般解决方案适用:记录类并检查/比较新类与之前的类。
答案 1 :(得分: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;
}
}