使用构造函数参数实例化泛型类型?

时间:2017-05-27 02:27:07

标签: java inheritance types

我现在面临一个非常令人困惑的问题。

我正在开发程序库的扩展。在所述库中,有多个类 A,B,C和D ,它们都继承自同一个超类 Base

现在,我为每个类 A1,B1,C1和D1 制作单独的扩展,这些类都继承自 A,B,C和D 分别。除此之外,他们都实现了自定义界面 I1 ,我自己也加入了。

base的构造函数(以及所有子类,包括我的)接受一个 E 类型的参数。

为了以简单的方式实例化这些类,我试图编写一个在需要时创建实例的处理程序类。它应该是这样的:

public class Handler
{
    private Base ctype;
    public Handler(Class<T extends Base implements I1> ctype)
    {
          this.ctype = new ctype.class(E.instance);
    }
}

现在,当然它并没有这样做,但我确信我已经明白了这个想法。

截至目前,我有一个扩展的工作版本,虽然非常草率,因为我代替处理程序类,手动检查每个类型并实例化正确的对象。由于我将来要修改更多的课程,我不惜一切代价避免这种情况,以避免文件混乱。

我知道ctype.newInstance()方法,但是由于Base类在其构造函数中需要一个参数,我担心它不会工作。 (除非我错过了什么,在这种情况下,请指出我!)

感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

好吧,您可以使用例如getConstructor(Class...)来获取一个非默认无参数的构造函数。

你会有这样的事情:

import java.lang.reflect.*;

public class Handler<B extends Base & I1> {
    private E instanceOfE = ...; // Not sure where you get the E from.
    private Constructor<B> ctor;

    public Handler(Class<B> ctype) {
        if (Modifier.isAbstract(ctype.getModifiers())) {
            throw new IllegalArgumentException(ctype + " is abstract");
        }
        if (!Modifier.isPublic(ctype.getModifiers())) {
            throw new IllegalArgumentException(ctype + " is not public");
        }
        try {
            ctor = ctype.getConstructor(E.class);
        } catch (NoSuchMethodException x) {
            throw new IllegalArgumentException(x);
        }
        Arrays.stream(ctor.getExceptionTypes())
              .filter(x -> !RuntimeException.class.isAssignableFrom(x)
                        && !Error.class.isAssignableFrom(x))
              .findFirst()
              .ifPresent(x -> throw new IllegalArgumentException(ctor + " declares a checked exception");
    }

    private B create() {
        try {
             return ctor.newInstance(instanceOfE);
        } catch (InvocationTargetException x) {
             Throwable cause = x.getCause();
             if (cause instanceof RuntimeException)
                 throw (RuntimeException) cause;
             if (cause instanceof Error)
                 throw (Error) cause;
             // This won't happen because we checked for
             // it in the constructor.
             throw new RuntimeException(cause);
        } catch (IllegalAccessException
               | InstantiationException x) {
             // These also won't happen because we checked
             // for it in the constructor.
             throw new RuntimeException(x);
        }
    }
}

但是,我并不是所有人都相信你需要使用反射。你现在可以使用lambda表达式和方法引用来做这类事情,而且通常会好得多。

不是传递一个类,而是传递某种Function<E, Base>

public class Handler<B extends Base & I1> {
    public Handler(Function<E, B> ctorFn) {
        Base b = ctorFn.apply(instanceOfE);
    }
}

然后使用方法引用创建新的处理程序:

Handler<A1> h = new Handler<>(A1::new);

反思很好而且非常强大,但现在并不总是这种事情的最佳方式。

答案 1 :(得分:2)

要调用带参数的构造函数,请使用getConstructor(Class<?>...)获取ConstructorConstructornewInstance()方法接受参数。

this.ctype = ctype.getConstructor(E.class).newInstance(E.instance);

异常处理留给读者练习。