为什么这个泛型不能识别它的超类边界(Java)?

Nic*_*ole 7 java generics

我有一个对象实例系统,其中包含对定义对象的引用.我为每个继承树都有一个顶级类.实例对象具有对应定义类的通用引用.

在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)

我对思原因是,如果你想有一个BeargetDef()方法返回一个BlackBearDef,即Bear基准还要进行参数设置为Bear<BlackBearDef>.在那种情况下(无论如何你的例子)你有效地知道它是BlackBear来自声明的类型,所以你可能只是将它称为a BlackBear.也就是说,它显然并非总是如此简单,你的实际情况可能不允许这样.

  • @Renesis:不,它只知道它至少是一个'Def`."熊<D延伸BearDef>"的删除扩展Animal <D>`简单地说就是"熊伸展动物".而且`Animal.getDef()`的最小界限只是一个`Def`,而不是一个`BearDef`.基本上,一旦你开始使用原始类型(声明为参数化但你没有在使用点参数化的类型),你已经没收了泛型可以给你的一切,你又回到了擦除的形式. (4认同)
  • @Renesis:你会这么认为,但是当你使用原始类型时,任何与泛型(包括)相关的东西都会消失.你永远不应该使用参数化类型的原始形式,除非你绝对需要(很少应该从不). (2认同)