Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用new关键字创建单个对象_Java_Singleton - Fatal编程技术网

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

Java 使用new关键字创建单个对象,java,singleton,Java,Singleton,以下问题由项目总监第四轮访谈提出 有一个a班。可以从A派生任意数量的类。约束是从A或A本身派生的任何子类,我应该能够使用new关键字为每个类创建一个对象。如果我尝试创建另一个对象,它将抛出异常 类B是类C的派生类,类D、类E也是派生类。班级人数不限。可以派生任意数量的类 限制逻辑必须在类继承权内,而不是在主类内 A obj1 = new A(); // object should create A obj2 = new A(); // exception should throw E Ob

以下问题由项目总监第四轮访谈提出

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

类B是类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
主类的示例代码

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

在类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());
}
}
这应该足以让你开始

记录在案:虽然这应该有效,但这似乎是一个相当奇怪的想法。如果您需要单例对象,可以考虑使用枚举作为例子。这将防止所有微妙的问题,例如,由于多线程创建对象

或者,正如评论所指出的:这些物体的寿命如何?您可以使用映射来确保保留对您的单例的引用


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

在类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());
}
}
这应该足以让你开始

记录在案:虽然这应该有效,但这似乎是一个相当奇怪的想法。如果您需要单例对象,可以考虑使用枚举作为例子。这将防止所有微妙的问题,例如,由于多线程创建对象

或者,正如评论所指出的:这些物体的寿命如何?您可以使用映射来确保保留对您的单例的引用


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

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

您可以在a中使用静态实例,然后在构造函数中检查实例是否存在,如果存在,则引发异常,如果没有,则创建一个对象。我假设任何类中只有一个对象是A或A的子类。如果你的意思是说每个子类和A都应该只有一个实例,然后,您可能需要创建一个静态HashMap,将类名作为中的键,然后通过从HashMap中检查类名来检查特定类是否存在实例。

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

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 {
}
产生如下输出:

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)
这只是利用了超类的构造函数总是在子类的实例创建时被调用这一事实。这甚至适用于任意的继承深度


有其他方法可以跟踪已实例化的类,其中一种是存储类,但我认为必要的部分是检查构造函数中可以看到运行时类的类型,为了防止成功实例化,在为时已晚之前

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

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 {
}
产生如下输出:

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)
这只是利用了超类的构造函数总是在子类的实例创建时被调用这一事实。这甚至适用于任意的继承深度

有其他方法可以跟踪已实例化的类,其中一种是存储类,但我认为必要的部分是检查构造函数中可以看到运行时类的类型,以免太迟而无法成功实例化

但是,类A也有子类,当创建子类对象时,将调用的构造函数。我希望您提到,这应该在单例中使用。构造函数不需要知道它是否已经被调用过一次,特别是在继承的上下文中。我很欣赏它的快速恢复。@Logan这本可以工作,但是,类A也有子类,当创建子类对象时,将调用构造函数。我希望您提到过,应该在单例中使用它。构造函数不需要知道它是否已经被调用过一次,特别是在继承的上下文中。我很欣赏这种快速恢复。特别是因为当GC收集它所能收集的内容时,需要实现finalize以从集合中释放类,但当然我不会在finalize方法中添加这种逻辑,因此,除非集合成为一个映射,成为一个Mutliton`Multi+singleton,这将永远不可用。特别是因为当GC收集它能收集的东西时,需要实现finalize才能从集合中释放类,但当然我不会在finalize方法中添加这种逻辑,所以除非集合成为一个映射,成为一个Mutliton`Multi+singleton,这将永远无法使用。您想为您的解决方案提供一个有趣的解决方案吗?a=新的a{};。现在,这还不能被看作是一门课。。。不是真的。@AxelH是的。。。但是这并没有破坏面试问题的答案,因为新的A{}实际上是一个不同的子类。所以只创建了一个实例。完全同意。但是有了这个,我仍然可以生成任意多的实例。我可以循环生成无限多的匿名类,直到集合重载为止。由于这不是同一个类,我不认为简单地拒绝任何getClass是正确的。这只是说明问题本身并不理想,这需要一些界限。@AxelH没错。这个问题可能只是为了测试解决问题的能力。这是一个很好的例子,一个无用的问题有。。。但是您不能在一个循环中创建多个内部类实例,因为它实际上是同一个类Main$1。你只能通过动态地生成类来绕过它,比如使用javassist。我不知道!从来没有想过用它来诚实;你想要一个有趣的解决方案吗?a=新的a{};。现在,这还不能被看作是一门课。。。不是真的。@AxelH是的。。。但是这并没有破坏面试问题的答案,因为新的A{}实际上是一个不同的子类。所以只创建了一个实例。完全同意。但是有了这个,我仍然可以生成任意多的实例。我可以循环生成无限多的匿名类,直到集合重载为止。由于这不是同一个类,我不认为简单地拒绝任何getClass是正确的。这只是说明问题本身并不理想,这需要一些界限。@AxelH没错。这个问题可能只是为了测试解决问题的能力。这是一个很好的例子,一个无用的问题有。。。但是您不能在一个循环中创建多个内部类实例,因为它实际上是同一个类Main$1。你只能通过动态地生成类来绕过它,比如使用javassist。我不知道!从来没有想过用它来诚实;