似乎我再次陷入了Java泛型。这就是我所拥有的:
几堂课:
class CoolIndex implements EntityIndex<CoolEntity>
class CoolEntity extends BaseEntity
使用上述类的枚举:
enum Entities {
COOL_ENTITY {
@Override
public <E extends BaseEntity, I extends EntityIndex<E>> Class<I> getIndexCls() {
return CoolIndex.class;
}
@Override
public <E extends BaseEntity> Class<E> getEntityCls() {
return CoolEntity.class;
}
}
public abstract <E extends BaseEntity, I extends EntityIndex<E>> Class<I> getIndexCls();
public abstract <E extends BaseEntity> Class<E> getEntityCls();
}
我需要使用getIndexCls()
函数调用的结果调用函数:
static <E extends BaseEntity, I extends EntityIndex<E>> boolean isSomeIndexViewable(Class<I> cls)
问题是编译器抱怨return CoolIndex.class;
和return CoolEntity.class;
并且我不清楚为什么......当然我可以把它投到Class<I>
(第一种情况) )但在我看来,我似乎试图掩盖我的误解,并且感觉不对。
答案 0 :(得分:4)
getIndexCls
的问题在于,因为它是通用的,所以类型参数可以解释为适合声明边界的任何类。您可能认为CoolIndex.class
符合这些边界,并且确实如此,但是该方法的调用者可以提供它们自己的类型参数,这些参数是不兼容的,例如:
Entities.COOL_ENTITY.<UncoolEntity, UncoolIndex>getIndexCls();
这会破坏类型安全性,因此编译器不允许这样做。您可以强制转换为Class<I>
,但编译器会因为同样的原因警告您未经检查的强制转换。它会编译,但它可能导致运行时问题,如我所述。
其他情况可以通过传递Class<I>
对象来使类型推断正常工作来解决这种情况,但这会破坏此方法的重点 - 返回Class<I>
对象。
其他情况要求将泛型类型参数从方法移动到类,但是您使用的枚举不是通用的。
我想出的类似于编译的唯一方法是完全删除enum
。使用抽象类,以便声明类级别类型参数。用你想要的类型参数实例化常量。
abstract class Entities<E extends BaseEntity, I extends EntityIndex<E>> {
public static final Entities<CoolEntity, CoolIndex> COOL_ENTITY = new Entities<CoolEntity, CoolIndex>() {
@Override
public Class<CoolIndex> getIndexCls() {
return CoolIndex.class;
}
@Override
public Class<CoolEntity> getEntityCls() {
return CoolEntity.class;
}
};
// Don't instantiate outside this class!
private Entities() {}
public abstract Class<I> getIndexCls();
public abstract Class<E> getEntityCls();
}
答案 1 :(得分:1)
这可以通过更简单的例子再现:
public <E extends BaseEntity> E get() {
return new BaseEntity(); // compilation error here
}
此声明<E extends BaseEntity>
中的问题是您的方法声称返回调用者应该询问的任何类型E
的实例:
MyCoolEntity1 e = get(); // valid, E is MyCoolEntity1
MyCoolEntity2 e = get(); // valid, E is MyCoolEntity2
此代码应该是编译时安全的,因此您必须将方法的结果转换为E
public <E extends BaseEntity> E get() {
return (E) new BaseEntity(); // no error, but unsafe warning
}
在您的示例中它非常相似,您声称返回Class<E>
类型的值:
public <E extends BaseEntity> Class<E> getEntityCls()
但是返回SomeEntity.class
的具体课程Class<CoolEntity>
您可以添加类型广告return (Class<I>) CoolIndex.class;
/ return (Class<E>) CoolEntity.class;
您可以使用类替换枚举,因为枚举不能是通用的,类可以
您可以完全删除泛型,因为其中没有太多价值