java - 如何只创建一个父子对象
问题描述
设计一个类,使得只能创建该类的一个实例及其任何子类。澄清一下:假设 A 是这样一个类,而 B 是从 A 派生的。B 除了扩展 A 之外没有任何特殊代码。
class A {
// code of class A
}
public class B extends A{
public static void main(String[] args)
{
new A(); // works fine.
new A(); // causes an exception
new B(); // works fine as this is the first instance of B
new B(); // causes an exception.
}
}
但是我们需要使用new关键字创建对象。
我尝试在父级中定义静态值,但这没有帮助。
解决方案
class A {
private static Map<Class<? extends A>, A> instances = new HashMap<>();
public A() {
synchronized (A.class) {
if (instances.containsKey(this.getClass())) {
throw new IllegalStateException();
}
instances.put(getClass(), this);
}
}
// code of class A
}
public class B extends A {
public static void main(String[] args) {
new A(); // works fine.
new A(); // causes an exception
new B(); // works fine as this is the first instance of B
new B(); // causes an exception.
}
}
当您创建 的实例A
或任何子类时,将调用它A
的构造函数。A
构造函数检查 的实例A
是否存在于Map
instances
.
如果当前类的实例存在,则抛出异常。
如果当前类的实例不存在(当没有抛出异常时),则当前对象被保存到instances
.
在所有实例中使用的Map
都是static
相同的(如果每个实例都有自己的Map
,它显然不会工作)。A
Map
该块通过锁定对象来synchronized
确保映射访问是线程安全的。锁定当前对象不是线程安全的,因为在创建新对象时方法不是线程安全的。Class
A
Class
put
HashMap
您还可以按照oleg.cherednik的答案中所述锁定instances
或使用 a Set
of Class
es 。
推荐阅读
- javascript - 您如何摆脱警报框并恢复行动流程?- Javascript
- typescript - Jest 无法导入包,而我的其他打字稿代码导入它
- javascript - 打字稿:有条件地将对象属性标记为可选?
- java - 如何用 Jackson 序列化扩展 TreeSet 的类?
- mysql - 使用单个查询获取列中每个值的顶级类别
- r - 复制蒙蒂大厅游戏
- linux - Cgroup 意外地将 SIGSTOP 传播到父级
- lua - 如何将数据和表插入现有的?
- android - 你可以直接在android应用程序中链接静态库吗?
- php - mPDF - 用于生成 PDF 文件的 html 代码块内的 PHP 脚本