[英]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.