[英]Java self type recursive type parameters and inheritance error in javac
为什么此代码无法编译?
public class x
{
private void test()
{
handle(new ThingA());
handle(new ModifiedThingA());
}
private <T extends BaseThing<T>, X extends T> java.util.List<T> handle(X object)
{
return object.getList();
}
private static class BaseThing<T extends BaseThing<T>>
{
public java.util.List<T> getList()
{
return null;
}
}
private static class ThingA
extends BaseThing<ThingA>
{
}
private static class ModifiedThingA
extends ThingA
{
}
}
Java 6在handle(new ModifiedThingA());
给出了此错误handle(new ModifiedThingA());
:
x.java:6: <T,X>handle(X) in x cannot be applied to (x.ModifiedThingA)
handle(new ModifiedThingA());
^
Java 7甚至不喜欢handle(new ThingA());
,这是Java 7的输出:
x.java:5: error: invalid inferred types for T; inferred type does not conform to declared bound(s)
handle(new ThingA());
^
inferred: ThingA
bound(s): CAP#1
where T,X are type-variables:
T extends BaseThing<T> declared in method <T,X>handle(X)
X extends T declared in method <T,X>handle(X)
where CAP#1 is a fresh type-variable:
CAP#1 extends BaseThing<CAP#1> from capture of ?
x.java:6: error: invalid inferred types for T; inferred type does not conform to declared bound(s)
handle(new ModifiedThingA());
^
inferred: ModifiedThingA
bound(s): CAP#1
where T,X are type-variables:
T extends BaseThing<T> declared in method <T,X>handle(X)
X extends T declared in method <T,X>handle(X)
where CAP#1 is a fresh type-variable:
CAP#1 extends BaseThing<CAP#1> from capture of ?
2 errors
这在我看来, javac
被误认为ModifiedThingA
的BaseThing<ModifiedThingA>
时,它实际上是一个BaseThing<ThingA>
这是我的bug还是javac
?
javac
的行为似乎是正确的。 从理论上讲,一个类型变量T
就足够了。 但是,您引入了第二个类型变量X
,以帮助进行类型推断。 首先推断X
的参数,然后根据调用上下文推断T
的参数:
List<ThingA> a = handle(new ThingA());
List<ThingA> b = handle(new ModifiedThingA());
但是,您的调用上下文不会对返回类型施加任何限制。 因此,编译器被迫引入以空类型为下限的类型变量( CAP#1
)。 T
的参数将推断为glb(BaseThing<CAP#1>) = BaseThing<CAP#1>
。 给定其下限, X
不能证明是T
的子类型。
有两种或三种方法可以解决此问题。
T
与它的bounds参数断开连接 我更喜欢选项3:
private <T extends BaseThing<T>> List<T> handle(BaseThing<? extends T> object) {
return new ArrayList<T>(object.getList());
// or (using guava's ImmutableList)
return ImmutableList.copyOf(object.getList());
}
快乐的仿制药。
您的代码可以在javac 1.8.0_45和Eclipse 4.1.1中很好地编译。
为了更好地编译lambda表达式,对Java 8中的类型推断算法所做的更改可能也解决了您的问题。
javac 1.7.0_09和1.7.0_11中似乎存在一个错误,这会导致此问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.