在 Java 中使用递归泛型时类型不兼容
Incompatible types when using recursive generics in Java
我写了 java code,其中我使用泛型的递归形式来实现使构建器模式可继承的简洁方法。
这有效,但我不明白我从 java 编译器收到的一些警告和错误。
这是我不明白的部分的严重简化版本:
package nl.basjes.test;
public class Foo<X extends Foo<X>> {
public X doSomething() {
return this;
}
}
对于 "return this;" 我得到错误
Incompatible Types
Required: X
Found : nl.basjes.test.Foo <X>
现在 'this' 始终是 Foo 的子类(甚至是 Foo 本身)并且 'X' 被定义为 X extends Foo<X>
。
据我所知,这些应该是 "the same",但显然不是。
所以在我的代码中,我向 return 语句添加了一个转换,如下所示:
package nl.basjes.test;
public class Foo<X extends Foo<X>> {
public X doSomething() {
return (X)this;
}
}
这使得代码按预期和预期编译和工作。
然而,出于与上述相同的原因,我仍然收到关于 "Unchecked cast" 的警告(但现在它只是一个警告)。
$ 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>
)兼容?
在这一点上,我最好的猜测是这与我还不理解的类型擦除的一部分有关。
当你考虑具体的类型参数时,问题就变得更容易了:
假设
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()
到return一个Bar
,但是doSomething()
中的代码是return一个Baz
,但将其转换为 Bar
,这存在类型安全问题(事实上,这些类型是不兼容的,但只有当您具有与上一个示例不同的 类 时,才会出现 classcastexception)。
我写了 java code,其中我使用泛型的递归形式来实现使构建器模式可继承的简洁方法。
这有效,但我不明白我从 java 编译器收到的一些警告和错误。
这是我不明白的部分的严重简化版本:
package nl.basjes.test;
public class Foo<X extends Foo<X>> {
public X doSomething() {
return this;
}
}
对于 "return this;" 我得到错误
Incompatible Types
Required: X
Found : nl.basjes.test.Foo <X>
现在 'this' 始终是 Foo 的子类(甚至是 Foo 本身)并且 'X' 被定义为 X extends Foo<X>
。
据我所知,这些应该是 "the same",但显然不是。
所以在我的代码中,我向 return 语句添加了一个转换,如下所示:
package nl.basjes.test;
public class Foo<X extends Foo<X>> {
public X doSomething() {
return (X)this;
}
}
这使得代码按预期和预期编译和工作。
然而,出于与上述相同的原因,我仍然收到关于 "Unchecked cast" 的警告(但现在它只是一个警告)。
$ 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>
)兼容?
在这一点上,我最好的猜测是这与我还不理解的类型擦除的一部分有关。
当你考虑具体的类型参数时,问题就变得更容易了:
假设
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()
到return一个Bar
,但是doSomething()
中的代码是return一个Baz
,但将其转换为 Bar
,这存在类型安全问题(事实上,这些类型是不兼容的,但只有当您具有与上一个示例不同的 类 时,才会出现 classcastexception)。