我现在面临一个非常令人困惑的问题。
我正在开发程序库的扩展。在所述库中,有多个类 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类在其构造函数中需要一个参数,我担心它不会工作。 (除非我错过了什么,在这种情况下,请指出我!)
感谢您的帮助!
答案 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<?>...)
获取Constructor
。 Constructor
有newInstance()
方法接受参数。
this.ctype = ctype.getConstructor(E.class).newInstance(E.instance);
异常处理留给读者练习。