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

Nie*_*jes 3 java generics incompatibletypeerror

我编写了java代码,我使用递归形式的泛型来实现一种使Builder模式可继承的简洁方法.

这有效,但我不明白我从java编译器得到的一些警告和错误.

这是我不理解的部分的严重简化版本:

package nl.basjes.test;

public class Foo<X extends Foo<X>> {
  public X doSomething() {
    return this;
  }
}
Run Code Online (Sandbox Code Playgroud)

对于"归还这个"; 我收到了错误

Incompatible Types
Required: X
Found   : nl.basjes.test.Foo <X>
Run Code Online (Sandbox Code Playgroud)

现在'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;
  }
}
Run Code Online (Sandbox Code Playgroud)

这使代码编译和按预期和预期工作.

然而,由于与上述相同的原因,我仍然会收到关于"未经检查的演员表"的警告(但现在它只是一个警告).

$ 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
Run Code Online (Sandbox Code Playgroud)

为什么Java没有看到X(扩展Foo<X>)和this(扩展Foo<X>)兼容?

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

ern*_*t_k 5

当您考虑具体类型参数时,更容易看到问题:

假设

Foo<Bar> barFoo = ...;
Run Code Online (Sandbox Code Playgroud)

当你打电话时barFoo.doSomething(),你希望得到一个Bar对象:

Bar bar = barFoo.doSomething()
Run Code Online (Sandbox Code Playgroud)

但是,您的实际实施:

public X doSomething() {
  return this;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

class Bar extends Foo<Bar> {
}
class Baz extends Foo<Bar> { //note this is a Foo<Bar>
}
Run Code Online (Sandbox Code Playgroud)

和:

Baz baz = new Baz();
Bar bar = baz.doSomething();
Run Code Online (Sandbox Code Playgroud)

在上面,你希望baz.doSomething()返回一个Bar,但是代码中的doSomething()是返回a Baz,但是将其转换Bar为具有类型安全问题(实际上,这些类型是不兼容的,但是当你有不同的类时,你只会获得classcastexception在最后一个例子中).