2015-01-10 100 views
1

我知道編譯器使用目標類型來確定使泛型方法調用適用的類型參數。例如,在下面的語句:目標類型具有通配符時的通用方法類型推斷

List<String> listOne = Collections.emptyList(); 

其中Collections.emptyList有一個類型參數T在其簽名

public static final <T> List<T> emptyList() { 

在這種情況下,T推斷出的類型參數是String

現在考慮以下幾點:

List<?> listTwo = Collections.emptyList(); 

什麼是在這種情況下,推斷出的類型?是Object?或者,由於通配符告訴編譯器任何類型都是可能的,它並不重要。

+0

它只是'?'。 –

+0

'?'不是「任何類型」,它是「未知類型」。除此之外,奧利弗說。 – markspace

+0

作爲一個切線,目前還不清楚你會用'List '做什麼,因爲你不能放任何東西。 –

回答

4

通配符的每個用法都有與其相關的不同類型。 (通常情況下,JLS是指此爲一個「清爽型」)。這是怎麼例如像這樣的編譯器錯誤的原理:

List<?> list0 = ... ; 
List<?> list1 = ... ; 
list0.add(list1.get(0)); // error 

,因爲它是list0list1是由編譯器給出不同的類型的情況下使得大部分

reference_type_of(List<?>) != reference_type_of(List<?>) 

你可以開始看到如何適應如果您嘗試類似

{ 
    List<?> list0 = ... ; 
    List<?> list1 = ... ; 
    test(list0, list1); 
} 
static <T> void test(List<T> list0, List<T> list1) {} 

凡類型推斷編譯器會發出一個錯誤,實際上告訴我們一些關於它爲list0list1生成的類型。

 
error: method test in class Ideone cannot be applied to given types; 
    test(list0, list1); 
    ^
    required: List<T>,List<T> 
    found: List<CAP#1>,List<CAP#2> 
    reason: no instance(s) of type variable(s) T exist so that 
      argument type List<CAP#2> conforms to formal parameter type List<T> 
    where T is a type-variable: 
    T extends Object declared in method <T>test(List<T>,List<T>) 
    where CAP#1,CAP#2 are fresh type-variables: 
    CAP#1 extends Object from capture of ? 
    CAP#2 extends Object from capture of ? 

期間capture conversion產生這些CAP#...類型(我的粗體。強調)。它向我們展示的是,當檢查方法調用表達式時,list0list1被賦予了彼此不同的類型。 (對於那些需要解釋的錯誤。這是因爲test聲明稱,兩份名單必須有相同的T

所以,因爲我們現在知道,一個通配符被相關的引用類型,我們可以看到在像

List<?> empty = Collections.emptyList(); 

情況下的調用將被推斷爲像「新鮮的類型,其中上限是對象」。或者象徵性地我們可以說,編譯器可能會看到類似

// target type  -->  inferred invocation type 
//  v       v 
List<CAP#1> empty = Collections.<CAP#1>emptyList(); 

雖然:當然,我們一直在猜測一點點,因爲這完全取決於它如何實現這個編譯器。理論上,對於上述emptyList()這樣微不足道的分配情況,它不需要做任何工作來生成正確的字節碼。

此外,我很抱歉,我不覺得今天spec掃描。基本上,這裏的類型推斷通過生成一組約束來演示方法調用應該或不應該編譯。在18.5.2中描述的算法以這種方式包含通配符。

0

What is the inferred type in this case? Is it Object? Or it doesn't really matter due to the wildcard telling the compiler any type is possible?

在一個層面上,這是怎樣的一個哲學問題的,因爲類型參數沒有對字節碼編譯任何影響,因此它並不真正的問題是什麼特別。唯一重要的是是否不可能滿足範圍和上下文。只要編譯器可以證明存在某種類型可以工作,那麼在我看來,它應該能夠繼續編譯而不需要提出實際的類型。