Java:嵌套递归泛型

Java: Nested recursive 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 方法中的编译器错误。我做错了什么,我该如何解决?

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

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

你的基础class被声明为BaseEntity<E extends BaseEntity>,这意味着在这个方法中:

E getNewInstance()

擦除是

BaseEntity getNewInstance();

这意味着 c.getNewInstance() return 是 BaseEntity,而不是 Collection,这就是您的编译错误所在。

另一方面,

Document 不是 通用 class。这意味着擦除在编译时并不重要(出于这些目的),并且 getNewInstance() returns E 表示的类型,在这种情况下是 Document .因此,d.getNewInstance() 的 return 类型为 Document,因此该行可以正常编译。


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

BaseEntity<E extends BaseEntity>

您已将 BaseEntity 定义为泛型 class -- 但随后立即忽略了 E extends BaseEntity 中的泛型。该行应该改为:

BaseEntity<E extends BaseEntity<E>>

这个构造函数的问题

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

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

的类型

任何像 Document 这样扩展 Collection 的 class 必须提供自己的 class,因此它将调用另一个 Collection 构造函数Class<E> 无论如何,所以我认为 Collection() 构造函数没有任何用处。我会删除它。

此外,在 E 的上限中,您使用的是您正试图使其通用的 classes 的原始形式。使用

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

Document 也必须作为类型参数提供给 Collection,因为 DocumentCollection<Document>

Collection<Document> cd = new Document();
cd = cd.getNewInstance();