Java:嵌套递归泛型

时间:2015-01-27 21:08:47

标签: java generics

我有一组扩展一些基本实体的类。此集合中的类也可以相互扩展,从而创建嵌套层次结构。

我的目标是所有类都可以访问创建自己的新实例的方法。我想在我的基本实体中实现此方法,以便所有扩展类继承此方法。

以下是为我的模式定义的三个示例类:

BaseEntity.java

public abstract class BaseEntity<E extends BaseEntity> {

    Class<E> clazz;

    public BaseEntity(Class<E> clazz) {
        this.clazz = clazz;
    }

    public E getNewInstance() throws IllegalAccessException, InstantiationException {
        return clazz.newInstance();
    }

}

Collection.java

public class Collection<E extends Collection> extends BaseEntity<E> {

    public Collection() {
        super(Collection.class); 
        // compiler error: BaseEntity (java.lang.Class<E>) in BaseEntity cannot be applied to
        //                            (java.lang.Class<Collection>)
    }

    public Collection(Class<E> clazz) {
        super(clazz);
    }

}

Document.java

public class Document extends Collection<Document> {

    public Document() {
        super(Document.class);
    }

}

通过这种设置,我希望能够做到这样的事情:

Collection c = new Collection();
c = c.getNewInstance(); // compiler error

Document d = new Document();
d = d.getNewInstance();

Collection cd = new Document();
cd = cd.getNewInstance(); // compiler error

但请注意Collection.java的默认构造函数中存在编译器错误。我不确定为什么会造成这种情况,我认为这也会导致样本main方法中的编译器错误。我做错了什么,如何解决这个问题?

请注意,这是一个人为的例子,涉及我试图解决的更大问题。我知道这个实现本身看起来很傻。

2 个答案:

答案 0 :(得分:8)

Collection<E...>是一种通用类型,但您的Collection c是原始类型。这意味着其所有方法将被视为原始类型,这意味着它们将返回任何通用的擦除。

您的基类声明为BaseEntity<E extends BaseEntity>,这意味着在此方法中:

E getNewInstance()
擦除是

BaseEntity getNewInstance();

这意味着c.getNewInstance()会返回BaseEntity,而不是Collection,这是编译错误的来源。

另一方面,

Document 不是一个泛型类。这意味着擦除在编译时并不重要(出于这些目的),getNewInstance()返回E表示的类型,在本例中为Document。因此,d.getNewInstance()的返回类型为Document,因此该行可以很好地编译。


顺便说一下:每当你有递归泛型时,你应该确保在递归中考虑泛型。例如,在这一行:

BaseEntity<E extends BaseEntity>

您已将BaseEntity定义为通用类 - 但随后会立即忽略E extends BaseEntity中的通用。该行应改为:

BaseEntity<E extends BaseEntity<E>>

答案 1 :(得分:3)

此构造函数的问题

public Collection() {
    super(Collection.class);
}

超类构造函数是否期望Class<E>,但类文字Collection.classClass<Collection>。这些类型不兼容,因为E可能是CollectionDocument或其他可能扩展Collection的内容。

任何扩展Document的{​​{1}}类都必须提供自己的类,因此无论如何都会调用另一个Collection构造函数,所以我不会#39;认为Collection构造函数有用。我会删除它。

此外,在Class<E>的上限中,您正在使用您尝试制作通用类的原始形式。使用

Collection()

E

类型public abstract class BaseEntity<E extends BaseEntity<E>> { 是通用的,因此您必须指定与public class Collection<E extends Collection<E>> extends BaseEntity<E> { 构造函数的参数匹配的泛型类型参数。

Collection

文档本身不是通用的,所以这段代码仍然很好:

Collection
即使直接创建Collection<Document> c = new Collection<Document>(Document.class); c = c.getNewInstance();

Document d = new Document(); d = d.getNewInstance(); 也必须作为Document的类型参数提供,因为CollectionDocument

Document