我有一个对象实例系统,其中包含对定义对象的引用.我为每个继承树都有一个顶级类.实例对象具有对应定义类的通用引用.
在getter中使用泛型,顶级对象的子类可以在不进行强制转换的情况下获得正确的定义类型.但是,再次进行子类化的抽象子类不能:
class Def { }
abstract class Animal<D extends Def> {
D def;
D getDef() { return def; }
}
class CatDef extends Def { }
class Cat extends Animal<CatDef> { }
abstract class BearDef extends Def { }
abstract class Bear<D extends BearDef> extends Animal<D> { }
class BlackBearDef extends BearDef { }
class BlackBear extends Bear<BlackBearDef> { }
class AnimalDefTest {
public static void main (String... args) {
Cat cat = new Cat();
CatDef catDef = cat.getDef(); // CatDef works fine
Bear bear = new BlackBear();
BearDef bearDef = bear.getDef(); // Error: Expected Def not BearDef? Why???
BearDef bearDef2 = ((Animal<BearDef>)bear).getDef(); // Works
}
}
Run Code Online (Sandbox Code Playgroud)
为什么getDef需要将a Bear转换为(Animal<BearDef>)才能获得BearDef?熊被最终定义为extends Animal<? extends BearDef>.
[ 编辑 ]更奇怪的是,如果我改变了熊类线:
abstract class Bear<D extends BearDef> extends Animal<BearDef> { }
Run Code Online (Sandbox Code Playgroud)
(在这种情况下D未被使用且无关紧要)它仍然不起作用.擦除D和以下行解决了上面代码中的错误(但不能帮助我做我需要做的子类定义):
abstract class Bear extends Animal<BearDef> { }
Run Code Online (Sandbox Code Playgroud)
Col*_*inD 11
你正在使用原始类型Bear,实际上它应该用一个类型参数化BearDef.如果你写的
Bear<BlackBearDef> bear = new BlackBear();
Run Code Online (Sandbox Code Playgroud)
要么
Bear<?> bear = new BlackBear();
Run Code Online (Sandbox Code Playgroud)
它工作正常.
另一件事:我不确定你打算如何使用它,但我觉得你很可能只是这样做:
abstract class Bear extends Animal<BearDef> {}
class BlackBear extends Bear {
// make use of covariant return type to make BlackBear return correct def
@Override
BlackBearDef getDef() { ... }
}
Run Code Online (Sandbox Code Playgroud)
我对思原因是,如果你想有一个Bear其getDef()方法返回一个BlackBearDef,即Bear基准还要进行参数设置为Bear<BlackBearDef>.在那种情况下(无论如何你的例子)你有效地知道它是BlackBear来自声明的类型,所以你可能只是将它称为a BlackBear.也就是说,它显然并非总是如此简单,你的实际情况可能不允许这样.