使用new关键字创建单个对象

时间:2018-05-29 04:45:17

标签: java singleton

以下问题由项目总监第四轮采访询问。

有一个A类。可以从A派生任意数量的类。约束是从A或A本身派生的任何子类,我应该能够使用new关键字为每个类创建一个对象。如果我尝试创建另一个对象,它将抛出异常。

Class B is derived class of A similarly class C, D, E are also derived classes. The number of class is not limited. Any number of classes can be derived.

B类是A的派生类,类似C类,D,E也是派生类。课程数量不限。可以派生任意数量的类。

限制的逻辑必须在不在主类内的类层次内。

主类的示例代码。

A obj1 = new A();  // object should create
A obj2 = new A();   // exception should throw
E Obj3 = new E();  //object should create
E obj4 = new E();   //Exception should throw

3 个答案:

答案 0 :(得分:3)

您可以通过将静态引用存储到包含实例化类的集合(可以是任何有效的数据结构),然后在构造函数中检查它以避免多个实例化来实现:

class A {
    private static Set<String> instantiatedClasses = new HashSet<>();

    A() {
        super();

        if (instantiatedClasses.contains(getClass().getName())) {
            throw new IllegalStateException(
                    "Cannot create multiple instances of " +getClass().getName());
        }

        instantiatedClasses.add(this.getClass().getName());
    }
}

class B extends A {
}

当测试时:

A a = new A();
System.out.println("Created a: " + a);
try {
    a = new A();
} catch (Exception e) {
    e.printStackTrace();
}

a = new B();
System.out.println("Created b: " + a);
a = new B();

产生这样的输出:

Created a: stackoverflow.A@506e1b77
java.lang.IllegalStateException: Cannot create multiple instances of stackoverflow.A
    at stackoverflow.A.<init>(Main.java:32)
    at stackoverflow.Main.main(Main.java:14)
Created b: stackoverflow.B@9807454
Exception in thread "main" java.lang.IllegalStateException: Cannot create multiple instances of stackoverflow.B
    at stackoverflow.A.<init>(Main.java:32)
    at stackoverflow.B.<init>(Main.java:40)
    at stackoverflow.Main.main(Main.java:21)

这只是利用了一个事实,即总是在为子类创建实例时调用超类的构造函数。这甚至可以用于任意继承深度。

还有其他方法可以跟踪已经实例化的类,其中一个是存储类,但我相信必要的部分是检查构造函数中的类型(可以看到运行时类,也可以在迟到以防止成功实例化)

答案 1 :(得分:2)

在A类中:有一组静态类。每次调用A的构造函数时,使用this.getClass()来获取想要实例化的实际类(请记住,任何子类都必须先调用超级构造函数。)

如果类存储在集合中,则抛出该异常。如果没有,则存储该类。

public class A {

private static final Set<Class<? extends A>> INSTANCE_HOLDER = new HashSet<>();

public A() {
    if (INSTANCE_HOLDER.contains(this.getClass()))
        throw new RuntimeException("can't create more than one instance.");

    INSTANCE_HOLDER.add(this.getClass());
}
}

这应该足以让你入门。

为了记录:尽管这应该有效,但这似乎是一个相当奇怪的想法。如果您需要单例对象,请考虑使用枚举。这将防止所有细微问题,例如由于多个线程创建对象。

或者,正如评论所指出的那样:这些物体的使用寿命如何?您可以使用地图来确保保留对单身人士的引用。

但最后,所有这些听起来都违反了单一责任原则。

答案 2 :(得分:0)

您可以在A中使用静态实例,然后在构造函数中检查实例是否存在,如果是,则抛出异常,如果不存在则创建对象。我假设任何类只有一个对象是A或A的子类。如果你的意思是说每个子类和A应该只有一个实例,那么你可能需要创建一个static HashMap with class Names作为A中的键,然后通过检查HashMap中的className来检查特定类是否存在实例。