如何使用超类中的构造函数创建子类的实例 [英] How to create instance of subclass with constructor from super class

查看:140
本文介绍了如何使用超类中的构造函数创建子类的实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想为类是超类的子类创建一个注册表。这些类存储在充当注册表的映射中。根据一个键从注册表中选择一个类,并通过反射创建该类的实例。

I'd like to create a registry for classes which are subclasses of a super class. The classes are stored in a map which acts as registry. A class is picked from the registry depending on a key and an instance of that class will be created via reflection.

我想根据构造函数实例化一个类超级类(带1个参数)。它只有在我在子类中声明构造函数时才有效。

I'd like to instantiate a class depending on a constructor (with 1 parameter) of the super class. It works only if I declare the constructor in the subclasses as well.

有没有办法使用超类的构造函数来实例化类?有没有办法让代码类型安全?

Is there a way to instantiate the class using a constructor of a super class? Is there a way to make that code type-safe?

示例代码:

public class ReflectionTest {

    /**
     * Base class with no-args constructor and another constructor with 1 parameter
     */
    public static class BaseClass {

        Object object;

        public BaseClass() {
            System.out.println("Constructor with no args");
        }

        public BaseClass( Object object) {
            this.object = object;
            System.out.println("Constructor with parameter= " + object);
        }

        public String toString() {
            return "Object = " + object;
        }
    }

    /**
     * Subclass with 1 parameter constructor
     */
    public static class SubClass1 extends BaseClass {
        public SubClass1( Object object) {
            super(object);
        }
    }

    /**
     * Subclass with no-args constructor
     */
    public static class SubClass2 extends BaseClass {

    }

    public static void main(String[] args) {

        // registry for classes
        Map<Integer,Class<?>> registry = new HashMap<>();
        registry.put(0, SubClass1.class);
        registry.put(1, SubClass2.class);

        // iterate through classes and create instances
        for( Integer key: registry.keySet()) {

            // get class from registry
            Class<?> clazz = registry.get(key);

            try {

                // get constructor with parameter
                Constructor constructor = clazz.getDeclaredConstructor( Object.class);

                // instantiate class
                BaseClass instance = (BaseClass) constructor.newInstance(key);

                // logging
                System.out.println("Instance for key " + key + ", " + instance);

            } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                e.printStackTrace();
            }

        }

        System.exit(0);
    }
}

该示例提供以下控制台输出:

The example gives the following console output:

Constructor with parameter= 0
Instance for key 0, Object = 0
java.lang.NoSuchMethodException: swing.table.ReflectionTest$SubClass2.<init>(java.lang.Object)
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.getConstructor(Class.java:1825)
    at swing.table.ReflectionTest.main(ReflectionTest.java:63)


推荐答案


  1. 超类不知道它的孩子。

  2. 构造函数不是继承的。

因此,如果不对子类ctor进行假设,则无法编写所需的代码。

Therefore, without making assumptions about the subclass ctor, you cannot write the code that you want.

那你能做什么?使用抽象工厂模式。

So what can you do? Use an Abstract Factory pattern.

我们可以创建一个接口工厂

@FunctionalInterface
public interface SuperclassFactory {
    Superclass newInstance(Object o);
}

您可以在工厂上创建多个方法,但这会使lambdas不那么整洁。

You could create more than one method on the Factory, but that would make it less neat for lambdas.

现在你有一个 Map< Integer,SuperclassFactory> ,并填充它:

Now you have a Map<Integer, SuperclassFactory>, and populate it:

Map<Integer,SuperclassFactory> registry = new HashMap<>();
registry.put(0, SubClass1::new);
registry.put(1, SubClass2::new);

因此,为了使用此地图你只需做:

So, in order to use this Map you simply do:

for(final Map.Entry<Integer,SuperclassFactory> e: registry.entrySet()) {
    //...
    final BaseClass instance = e.getValue().newInstance(e.getKey());
    //...
}

如果您的子类没有适当的ctor,此代码将无法编译,因为没有可以使用的ctor引用。这是Good Thing(TM)。要使用当前 Subclass2 进行编译,您需要使用:

If your subclass does not have the appropriate ctor, this code will not compile as there will be no ctor reference that can be used. This is Good Thing (TM). In order to compile with the current Subclass2 you would need to use:

registry.put(1, obj -> new SubClass2());

现在我们有:


  1. 失去反思

  2. 获取编译时类型安全

  3. 失去了丑陋的演员阵容(虽然那是通过滥用反射) / li>
  1. Lost the reflection
  2. Acquired compile time type safety
  3. Lost the ugly cast (although that was through misuse of reflection)

NB循环遍历 Map entrySet()而不是 keySet()

N.B. loop through a Map's entrySet() not its keySet().

这篇关于如何使用超类中的构造函数创建子类的实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆