为什么这段代码不能编译?
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
{
}
}Java6在handle(new ModifiedThingA());中给出了这个错误
x.java:6: <T,X>handle(X) in x cannot be applied to (x.ModifiedThingA)
handle(new ModifiedThingA());
^Java7甚至不喜欢handle(new ThingA());,这是Java7的输出:
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的?
发布于 2012-08-22 02:48:28
javac的行为似乎是正确的。理论上,一个类型变量T就足够了。但是,您引入了第二个类型变量X来帮助进行类型推断。首先推断出X的参数,然后根据调用上下文推断出T的参数:
List<ThingA> a = handle(new ThingA());
List<ThingA> b = handle(new ModifiedThingA());但是,您的调用上下文不会对返回类型施加任何限制。因此,编译器被forced来引入一个类型变量(CAP#1),并将null类型作为下限。T的参数将被推断为glb(BaseThing<CAP#1>) = BaseThing<CAP#1>。考虑到它的下限,X不是T的子类型。
有两到三种方法可以解决这个问题。
T与其边界参数的连接
我更喜欢选项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());
}快乐的泛型。
发布于 2015-11-04 20:44:03
您的代码在javac 1.8.0_45和Eclipse4.1.1中可以很好地编译。
可能为了更好地编译lambda表达式而对Java 8中的类型推断算法所做的更改也解决了您的问题。
发布于 2013-01-22 00:48:40
在javac 1.7.0_09和1.7.0_11中似乎有一个bug,导致了这个问题。
https://stackoverflow.com/questions/12058384
复制相似问题