在Java中使用递归泛型时的不兼容类型

时间:2018-08-15 20:54:54

标签: java generics incompatibletypeerror

我写了java code,在其中我使用递归形式的泛型来实现使Builder模式可继承的干净方法。

这可行,但是我不理解从Java编译器得到的一些警告和错误。

这是我不了解的部分的简化版本:

package nl.basjes.test;

public class Foo<X extends Foo<X>> {
  public X doSomething() {
    return this;
  }
}

对于“返回此”;我收到错误

Incompatible Types
Required: X
Found   : nl.basjes.test.Foo <X>

现在'this'始终是Foo的子类(甚至Foo本身),并且'X'被定义为X extends Foo<X>。 据我所知,这些应该是“相同的”,但显然不是。

因此,在我的代码中,我向以下的return语句添加了强制类型转换:

package nl.basjes.test;

public class Foo<X extends Foo<X>> {
  public X doSomething() {
    return (X)this;
  }
}

这使得代码可以按预期的方式编译和运行。

但是由于与上述相同的原因,我仍然会收到有关“未检查的演员表”的警告(但现在只是警告)。

$ javac -Xlint:unchecked nl/basjes/test/Foo.java 
nl/basjes/test/Foo.java:5: warning: [unchecked] unchecked cast
        return (X)this;
                  ^
  required: X
  found:    Foo<X>
  where X is a type-variable:
    X extends Foo<X> declared in class Foo
1 warning

为什么Java认为X(扩展Foo<X>)和this(扩展Foo<X>)兼容?

在这一点上,我最好的猜测是,这与我尚不了解的部分类型擦除有关。

1 个答案:

答案 0 :(得分:5)

考虑具体类型参数时,更容易发现问题:

假设

Foo<Bar> barFoo = ...;

调用barFoo.doSomething()时,您期望得到一个Bar对象:

Bar bar = barFoo.doSomething()

但是,您的实际实现是

public X doSomething() {
  return this;
}

可以大致填充以下具体参数:

public Bar doSomething() {
  return this; //But "this" is a Foo<Bar>, not a Bar.
}

下面是一个不同的例子,以使其更加明显:

class Bar extends Foo<Bar> {
}
class Baz extends Foo<Bar> { //note this is a Foo<Bar>
}

并且:

Baz baz = new Baz();
Bar bar = baz.doSomething();

在上面,您期望baz.doSomething()返回一个Bar,但是doSomething()中的代码返回一个Baz,但将其强制转换为Bar ,它存在类型安全性问题(实际上,这些类型是不兼容的,但是只有在上一个示例中具有不同的类时,您才会获得classcastexception。)