我有一个对象实例系统,其中包含对定义对象的引用。对于每个继承树,我都有一个顶级类。实例对象具有对相应定义类的通用引用。
在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
}
}
为什么
getDef
要求将Bear
强制转换为(Animal<BearDef>
)才能获得BearDef
?最终将Bear定义为extends Animal<? extends BearDef>
。[编辑]甚至更陌生,如果我更改Bear类行:
abstract class Bear<D extends BearDef> extends Animal<BearDef> { }
(在这种情况下,D未使用且无关紧要)仍然无效。擦除D并在下面的代码行中解决了上面代码中的错误(但并不能帮助我完成子类定义所需的工作):
abstract class Bear extends Animal<BearDef> { }
最佳答案
实际上,您正在使用原始类型Bear
,但应使用BearDef
类型对其进行参数化。如果你写
Bear<BlackBearDef> bear = new BlackBear();
或者
Bear<?> bear = new BlackBear();
会很好的。
另一件事:我不确定您打算如何使用它,但是在我看来,您可以这样做:
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() { ... }
}
我想这的原因是,如果您想要一个
Bear
,其getDef()
方法返回一个BlackBearDef
,则该Bear
引用将需要参数化为Bear<BlackBearDef>
。在那种情况下(无论如何,对于您的示例),您实际上都知道它是声明类型的BlackBear
,因此您也可以将其称为BlackBear
。就是说,这显然并不总是那么简单,您的实际情况可能不允许这样做。