Jes*_*sse 8 java generics javac java-6 java-7
为什么这段代码不能编译?
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
{
}
}
Run Code Online (Sandbox Code Playgroud)
Java 6在handle(new ModifiedThingA());以下版本中给出了此错误:
x.java:6: <T,X>handle(X) in x cannot be applied to (x.ModifiedThingA)
handle(new ModifiedThingA());
^
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
在我看来,那javac是弄错ModifiedThingA了BaseThing<ModifiedThingA>,当它实际上是一个BaseThing<ThingA>.这是我的虫子还是javac?
javac的行为看来是正确的。理论上,一个类型变量T就足够了。但是,您引入了第二个类型变量X来帮助进行类型推断。首先推断for 的参数X,然后根据调用上下文T推断 for 的参数:
List<ThingA> a = handle(new ThingA());
List<ThingA> b = handle(new ModifiedThingA());
Run Code Online (Sandbox Code Playgroud)
但是,您的调用上下文不会对返回类型设置任何限制。因此,编译器被迫引入一个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());
}
Run Code Online (Sandbox Code Playgroud)
快乐的仿制药。
| 归档时间: |
|
| 查看次数: |
1832 次 |
| 最近记录: |