2014-07-19 23 views
3

我知道這是不可能的: new T其中T是一種通用類型,由於類型擦除。爲什麼我們可以在Java中創建通用模板的新實例而不是泛型?

爲什麼然後可以做類似new A<T>這樣的T是通用的?例如,爲什麼以下編譯?

static class A<T>{ 
    T t; 
    A(T t){ 
     this.t=t; 
    } 
} 

static class B<T>{ 

    A<T> create(T t){ 
     return new A<T>(t); 
    } 
} 

public static void main (String[] args) throws java.lang.Exception 
{ 
    A<Integer> a = new B<Integer>().create(3); 
} 

回答

6

因爲A<Integer>是在編譯和運行時定義良好的類型。

在概念上,中間步驟,之後:

new B<Integer>() 

您到.create(3)呼叫是等效於調用:

static class B { 
    A<Integer> create(Integer t){ 
     return new A<Integer>(t); 
    } 
} 
擦除之後

A<Integer>變得A,這是一種有效的類型。

你不能做new T,因爲T不是一個定義良好的類型,它只是一個標記。如果你確實需要,就可以得到相應的類,並使用類似實例T類型的對象:

public class GenericFactory { 
    <T> T create(Class<T> c) throws Exception { 
     return c.newInstance(); 
    } 
} 

,並用它喜歡:

new GenericFactory().create(Integer.class); 

是的,這是醜陋的。

0

這是由於類型擦除,你可以實例化new A<T>()。如果Java將泛型實現爲可實現的,那麼沒有用於找出T的運行時綁定的反射就無法工作。

通過擴展,這是由於對象類型的非泛型方面被通用化(可通過getClass()訪問),因此編譯器不可能發出能夠實例化任何類型T的字節碼,取決於呼叫地點。

0

您未創建通用模板的新實例。您正在使用通用模板創建對象的實例。

new A<T>(t); 

創建新的A,這不是通用的。編譯時你不一定知道什麼是T,但你知道該對象將是一個A。事實上,它的美妙之處在於,你不必預知什麼是T,它可以讓你創建如此強大的代碼,這些代碼可以重複使用。試想一下,如果你實現了Stack,那麼你對實際的內容類型將不感興趣。您有興趣處理好toppoppush操作。如果您不必預知元素是IntegerString還是其他類型,則可以優雅地編寫適用於許多不同類的通用代碼。

如果我必須預知什麼T,那麼我寧願說它是一個Object,然後就可以處理任何對象。我相信事實上這樣的事情發生在後臺。另外,另一種選擇是使用reflection,但那根本不會乾淨。

相關問題