假设我们得到了一些具有层次结构的类,如下所示:
abstract class Foo<T extends A>
class Bar extends Foo<B>
class Hesh extends Foo<C>
abstract class A
class B extends A
class C extends A
我想知道,如果可以在 Foo 中编写代码,则会在调用时创建 B 或 C 类型的对象相应的儿童班。例如
//inside of Foo body
public void populate() {
//Something like
Class current_t = T.class;
current_t.getConstructor();
//Create an instance of the object using reflection
}
因此,我想在父类中创建一个创建对象的方法,该类型在子类中定义。
答案 0 :(得分:4)
通常,这是通过向父类添加一个抽象方法来实现的,目的是创建这样一个实例,让子类实现这个方法:
public abstract class Foo<T extends A> {
protected abstract T newInstance();
}
public class Bar extends Foo<B> {
@Override protected final T newInstance() { return new B(); }
}
public class Hesh extends Foo<C> {
@Override protected final T newInstance() { return new C(); }
}
通过这种方式,您可以了解要实例化的具体类(无需反射)。
事实上,这被称为factory method pattern。
不幸的是,没有办法在运行时检索具体参数类型,因为它们已被删除。至少,您无法在课程Foo
中检索它。
另一种方法是提供一个采用类型标记的构造函数:
public abstract class Foo<T extends A> {
private final Class<T> type;
protected Foo(Class<T> type) {
this.type = Objects.requireNonNull(type);
}
private T newInstance() {
return type.newInstance();
}
}
public class Bar extends Foo<B> {
public Bar() {
super(B.class);
}
}
public class Hesh extends Foo<C> {
public Hesh() {
super(C.class);
}
}
这里的缺点是A
的子类必须具有无参数构造函数。
答案 1 :(得分:1)
Seelenvirtuose的方法比较干净,但是有一个somewhat hacky approach使用超类类型中的getActualTypeArguments
来获取相应的子类。获得孩子的课程后,您可以在newInstance
方法中使用populate
通过反思创建实例,如下所示:
@SuppressWarnings("unchecked")
public T populate() throws IllegalAccessException, InstantiationException {
return ((Class<T>) (((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0])).newInstance();
}