我有一组扩展一些基本实体的类。此集合中的类也可以相互扩展,从而创建嵌套层次结构。
我的目标是所有类都可以访问创建自己的新实例的方法。我想在我的基本实体中实现此方法,以便所有扩展类继承此方法。
以下是为我的模式定义的三个示例类:
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方法中的编译器错误。我做错了什么,如何解决这个问题?
请注意,这是一个人为的例子,涉及我试图解决的更大问题。我知道这个实现本身看起来很傻。
答案 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.class
是Class<Collection>
。这些类型不兼容,因为E
可能是Collection
,Document
或其他可能扩展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
的类型参数提供,因为Collection
是Document
。
Document