2015-05-28 51 views
12

如何引用< < T >>由編譯器在下面的代碼中處理,因爲該方法沒有允許推理T的參數?對列表中可以放置什麼類型的對象有什麼限制嗎?甚至在我將字符串添加到列表的行上發生了演員陣容?我的第一個想法是,沒有任何東西可以推斷T,T就成爲一個對象類型。提前致謝。如果參數化方法不是輸入參數,參數化方法如何解決<T>?

public class App { 

private <T> void parameterizedMethod() 
{ 
    List<T> list = new ArrayList<>(); 
    for(int i = 0; i < 10; i++) 
    { 
     list.add((T)new String()); //is a cast actually occurring here? 
    } 
} 

public App() 
{ 
    parameterizedMethod(); 
} 

public static void main(String[] args) { 
    new App(); 
} 
} 

回答

0
List<T> list = new ArrayList<>(); 
for(int i = 0; i < 10; i++) 
{ 
    list.add((T)new String()); //is a cast actually occurring here? 
} 

不,不投實際上是在那裏出現。如果您對list做了任何強制使其成爲List<T>的任何操作(例如返回它),那麼在編譯器插入真正的強制轉換的位置可能會導致ClassCastException s。

4

這是最初由18.1.3確定:

當推理開始時,通常是從類型參數聲明P1, ..., Pp和相關聯的推理變量α1, ..., αp列表生成的綁定集合。這樣的綁定集合構造如下。對於每個1≤升≤p):

  • 如果Pl沒有TypeBound,結合的αl <: Object出現在集合。

  • 否則,對於每個類型T通過&TypeBound限定,結合的αl <: T[P1:=α1, ..., Pp:=αp]出現在集合; [...]。

在推理結束時,綁定集得到「解決」,以推斷出的類型。沒有任何額外的上下文,綁定集將只包含基於類型參數聲明的初始邊界。

用類似αl <: Object的形式綁定的表示αl(推理變量)是ObjectObject的子類型。該界限解析爲Object

所以在你的情況下,是的,推測爲Object

如果我們宣佈一個綁定類型:

private <T extends SomeType> void parameterizedMethod() 

然後SomeType會被推斷。


在這種情況下(擦除)實際上不會發生轉換。這就是爲什麼它「未經檢查」。當對象被暴露由於例如: -

<T> T parameterizedMethodWithAResult() 
{ 
    return (T) new String(); 
} 

// the cast happens out here 
Integer i = parameterizedMethodWithAResult(); 
// parameterizedMethodWithAResult returns Object actually, 
// and we are implicitly doing this: 
Integer i = (Integer) parameterizedMethodWithAResult(); 

是否有任何限制被放置在什麼類型的對象可以被放置到列表中只投了會怎樣?

語義上(編譯時),是的。並注意限制是以外的的方法。 裏面的方法,我們不知道這個限制究竟是什麼。所以我們不應該把String置於List<T>。我們不知道T是什麼。

實際上(運行時),沒有。這只是一個List並沒有檢查演員。 parameterizedMethod不會導致例外 ...但只適用於這種隔離示例。這種代碼很可能導致問題。

+0

謝謝。自從我發現這一點以來,也非常有趣的是,編譯器強制我在將新的String添加到列表時將演員陣容保留至(T)。所以即使我們不知道T是什麼(儘管你指出它是一個Object),但我不得不將任何我添加到列表中的東西都施加到(T)。 – swingMan

+0

對,我們對'T'可能是什麼有一些想法,但我們並不完全知道。編譯器正在執行你未知的內容。 – Radiodef

1

在方法體內部,Java沒有辦法獲得關於T的替換的任何信息,那麼我們如何才能做到T有用的任何內容?

有時,T對方法體並不重要;它只是更方便調用者

public static List<T> emptyList(){...} 

    List<String> emptyStringList = emptyList(); 

但如果T是方法體中重要的是,必須有一個出帶外協議,而不是由編譯器執行,這兩個主叫方和被叫方都必須遵守。例如

class Conf 
    <T> T get(String key) 

// 
<conf> 
    <param name="size" type="int" ... 

// 
String name = conf.get("name"); 
Integer size = conf.get("size"); 

API使用<T>這裏只是讓來電者並不需要做一個明確的轉換。主叫方有責任確保提供正確的T

在你的例子中,被調用者假定T是一個超類型String;來電者必須堅持這一假設。這將是很好,如果這樣的限制可以表示編譯器爲

<T super String> void parameterizedMethod() 
{ 
    List<T> list 
    ... 
    list.add(new String()); // obviously correct; no cast is needed 
} 

// 
this.<Integer>parameterizedMethod(); // compile error 

不幸,Java不支持<T super Foo> ... :)所以,你需要的javadoc約束,而不是

/** T must be a supertype of String! **/ 
<T> void parameterizedMethod() 

我有這樣的實際API example