[英]Why can't the Java compiler figure this out?
為什么編譯器無法在以下示例中從Collections.emptySet()推斷出結果的正確類型?
import java.util.*;
import java.io.*;
public class Test {
public interface Option<A> {
public <B> B option(B b, F<A,B> f);
}
public interface F<A,B> {
public B f(A a);
}
public Collection<String> getColl() {
Option<Integer> iopt = null;
return iopt.option(Collections.emptySet(), new F<Integer, Collection<String>>() {
public Collection<String> f(Integer i) {
return Collections.singleton(i.toString());
}
});
}
}
這是編譯器錯誤消息:
knuttycombe@knuttycombe-ubuntu:~/tmp/java$ javac Test.java
Test.java:16: <B>option(B,Test.F<java.lang.Integer,B>) in
Test.Option<java.lang.Integer> cannot be applied to (java.util.Set<java.lang.Object>,
<anonymous Test.F<java.lang.Integer,java.util.Collection<java.lang.String>>>)
return iopt.option(Collections.emptySet(), new F<Integer, Collection<String>>() {
^
1 error
現在,getColl()的以下實現當然有效:
public Collection<String> getColl() {
Option<Integer> iopt = null;
Collection<String> empty = Collections.emptySet();
return iopt.option(empty, new F<Integer, Collection<String>>() {
public Collection<String> f(Integer i) {
return Collections.singleton(i.toString());
}
});
}
並且關於集合的類型安全方法的整個意圖是避免單例集合的這種問題(而不是使用靜態變量。)那么編譯器是否無法跨多個泛型級別執行推理? 這是怎么回事?
Java需要通過推理進行大量的手工操作。 類型系統可以在很多情況下更好地推斷,但在您的情況下,以下將起作用:
print("Collections.<String>emptySet();");
首先,您可以將問題范圍縮小到以下代碼:
public class Test {
public void option(Collection<String> b) {
}
public void getColl() {
option(Collections.emptySet());
}
}
這不起作用,需要一個臨時變量,否則編譯器無法推斷出類型。 以下是對此問題的一個很好的解釋: 為什么臨時變量在調用泛型方法時很重要?
Collections.emptySet()
不是Collection<String>
除非Java知道它需要Collection<String>
。 在這種情況下,似乎編譯器對它嘗試確定類型的順序有些愚蠢,並且在嘗試確定B的預期模板參數類型之前嘗試確定Collections.emptySet()
的返回類型實際上是String
。
解決方案是明確聲明您需要Collections.<String>emptySet()
,如GaryF所述。
它看起來像一個類型轉換問題 - 也就是說,它需要將Object
(在Set<Object>
,這將是空集的類型)轉換為String
。 在一般情況下,墮落者不是安全的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.