为什么这段代码不能编译?
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());
中给出了这个错误:
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>
.这是我的错误还是javac
的?
最佳答案
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
的子类型.
有两种或三种方法。
- 手动推断(如果很少需要,可以)
- 提供一个返回类型为 void 的“重载”(急需另一个名字)
- 如果返回的列表是不可变的或防御性副本,您可以断开类型参数
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());
}
快乐的泛型。
关于javac中java自类型递归类型参数和继承错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12058384/