2011-06-07 131 views
11

Java編譯器是否能夠從其上下文中推斷泛型靜態函數的類型作爲另一個泛型靜態函數的參數?推測嵌套靜態泛型函數的泛型類型

例如,我有一個簡單的Pair類:

public class Pair<F, S> { 

    private final F mFirst; 

    private final S mSecond; 

    public Pair(F first, S second) { 
     mFirst = checkNotNull(first); 
     mSecond = checkNotNull(second); 
    } 

    public static <F, S, F1 extends F, S1 extends S> Pair<F, S> of(F1 first, S1 second) { 
     return new Pair<F, S>(first, second); 
    } 

    public F first() { 
     return mFirst; 
    } 

    public S second() { 
     return mSecond; 
    } 

    // ... 
} 

而且我有下面的一般靜態函數:

public static <F, P extends Pair<F, ?>> Function<P, F> deferredFirst() { 
    return (Function<P, F>)DEFERRED_FIRST; 
} 

private static final Function<Pair<Object, ?>, Object> DEFERRED_FIRST = 
     new Function<Pair<Object,?>, Object>() { 

    @Override 
    public Object apply(Pair<Object, ?> input) { 
     return input.first(); 
    } 
}; 

哪我希望用如下(Collections2.transform is from Google Guava):

List<Pair<Integer, Double>> values = ... 
Collection<Integer> firsts = Collections2.transform(values, 
     Pair.deferredFirst()); 

編譯器抱怨到:

The method transform(Collection<F>, Function<? super F,T>) in the type 
Collections2 is not applicable for the arguments 
(List<Pair<Integer,Double>>, Function<Pair<Object,?>,Object>) 

因此,編譯器似乎無法將transform()推斷的類型傳播給deferredFirst(),因爲它認爲它們是對象。

強迫編譯器瞭解類型通過以下兩種方式運作:

Function<Pair<Integer, ?>, Integer> func = Pair.deferredFirst(); 
Collection<Integer> firsts = Collections2.transform(values, func); 


Collection<Integer> firsts = Collections2.transform(values, 
     Pair.<Integer, Pair<Integer, ?>>deferredFirst()); 

是否有可能改變任何一個函數的簽名,讓編譯器推斷/傳播的類型?

編輯:對於波西米亞,這裏是一個可能的方法上面的例子可以用於:

public static int sumSomeInts(List<Pair<Integer, Double>> values) { 
    Collection<Integer> ints = Collections2.transform(values, 
      Pair.deferredFirst()); 
    int sum = 0; 
    for(int i : ints) 
     sum += i; 
    return sum; 
} 
+2

要小心,當你有'A級 {公共無效方法(){}}'。我的猜測是,'樓S'的方法來覆蓋從你的類{){}公共無效方法(}' – toto2 2011-06-07 12:57:20

回答

4

類型推斷是討厭和複雜的。他們必須在某個地方停下來。考慮

static <T> T foo(); 

String s = foo(); 

print(foo()) 

在分配方面,程序員的意圖很明顯,TString

下一行,沒有這麼多。

print方法不是一個很好的例子,它是沉重的重載。假設print沒有超載,其參數類型是固定的,所以T可以清楚地推斷出來。編譯器是否應該足夠聰明以解決問題?

這聽起來很合理,直到有人冒險閱讀相關規範文本,15.12 Method Invocation Expressions好運氣改變了那個爛攤子裏的東西!

它太複雜了,即使編譯器作者也不理解它。 javac和其他編譯器中有大量的bug來源於這部分規範。

+0

謝謝,很高興有一些背景信息 – Hal 2011-06-07 14:54:29

1

試試這個仿製藥的功夫:

public static int sumSomeInts(List<Pair<Integer, Double>> values) { 
    Collection<Integer> ints = Collections2.transform(values, 
     Pair.<Integer, Double>deferredFirst()); 
    int sum = 0; 
    for(int i : ints) 
     sum += i; 
    return sum; 
} 

可以鍵入方法調用和將泛型傳遞給下一個呼叫。

我不確定這裏使用的確切泛型參數,因爲您沒有包含足夠的代碼。如果你粘貼問題的整個方法,我將編輯這個答案,使其編譯。 編輯:從問題的新信息

請讓我知道它是否編譯。如果不是這個解決方案,它會很接近。關鍵是使用Class.<Type>staticMethod()語法鍵入靜態方法。

+0

我用一個簡單的例子方法編輯。 – Hal 2011-06-07 13:15:09

+0

的那些(即相當於'A級感謝您的幫助,因爲沒有明確的添加類型到嵌套的調用沒有解決方案我已經接受了不可信的答案,因爲它有更多關於這個問題的一般信息 – Hal 2011-06-07 14:48:27

1

我就怎麼了前一段時間是:

@SuppressWarnings("rawtypes") 
private static final Function ExtractFirst = new Function() { 
    @Override 
    public Object apply(final Object from) { 
     Preconditions.checkNotNull(from); 
     return ((Pair)from).first; 
    } 
}; 

@SuppressWarnings("unchecked") 
public static <A> Function<Pair<A,?>,A> extractFirst() { 
    return ExtractFirst; 
} 

不要讓「SuppressWarnings」把你趕走,它工作正常。

例子:

List<Pair<String,String>> pairs = ImmutableList.of(Pair.of("a", "b"), 
    Pair.of("c", "d"),Pair.of("e", "f")); 
Iterable<String> firsts = Iterables.transform(pairs, 
    Pair.<String>extractFirst()); 

可惜的是,你必須在一般的參數提供給extractFirst()。我認爲這是你得到的最好的。

+0

And 'firsts'會是[「a」,「c」,「e」],對不對? – Ray 2011-06-09 18:30:04