如何创建继承的泛型类的对象

时间:2015-08-18 06:17:40

标签: java generics inheritance

假设我们得到了一些具有层次结构的类,如下所示:

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
}

因此,我想在父类中创建一个创建对象的方法,该类型在子类中定义。

2 个答案:

答案 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();
}