如何使用超类中的构造函数创建子类的实例

Rol*_*and 16 java

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

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

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

示例代码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

Bor*_*der 13

  1. 超类不知道它的孩子.
  2. 构造函数不是继承的.

因此,在不对子类ctor进行假设的情况下,您无法编写所需的代码.

所以,你可以做什么?使用抽象工厂模式.

我们可以创建一个interface Factory:

@FunctionalInterface
public interface SuperclassFactory {
    Superclass newInstance(Object o);
}
Run Code Online (Sandbox Code Playgroud)

你可以创建多个方法Factory,但这会使lambda不那么整洁.

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

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

所以,为了使用它Map你只需:

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

如果您的子类没有相应的ctor,则此代码将无法编译,因为不会有可用的ctor引用.这是Good Thing(TM).Subclass2要使用当前编译,您需要使用:

registry.put(1, obj -> new SubClass2());
Run Code Online (Sandbox Code Playgroud)

所以现在我们有:

  1. 失去了反思
  2. 获取编译时类型安全性
  3. 失去了丑陋的演员阵容(尽管这是通过滥用反射)

NB循环通过MapentrySet()不是它keySet().