2014-02-26 113 views
3

我正在閱讀關於泛型中未知類型和原始類型的信息,並且想到了這個問題。換句話說,就是...Java,泛型:Set <?> s = HashSet <String>()和Set s = HashSet <String>()之間的區別是什麼?

Set<?> s = new HashSet<String>(); 

Set s = new HashSet<String>(); 

...同一個?

我試了一下,他們都似乎完成同樣的事情,但我想知道他們是否有任何不同的編譯器。

+3

嘗試通過'Set '添加一些內容(空值除外)。 – Pshemo

+0

[列表之間的差異,列表,列表,列表和列表](http://stackoverflow.com/questions/6231973/difference-between-list-list-listt-liste-and-listobject )另請參閱:[什麼是原始類型,爲什麼我們不應該使用它?](http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we -use-it) –

+1

**對我來說,這是一個很好的問題....爲什麼人們會投票結束它**:\ – NoobEditor

回答

6

不,他們是不一樣的。這裏的基本區別:

Set<?> s = HashSet<String>(); 
s.add(2); // This is invalid 

Set s = HashSet<String>(); 
s.add(2); // This is valid. 

的一點是,第一個是無界的參數化類型Set。編譯器將在那裏執行檢查,由於除了null之外不能添加任何內容,所以編譯器會給你一個錯誤。

雖然第二個是原始類型,編譯器在向其添加任何內容時不會執行任何檢查。基本上,你在這裏失去了類型安全。

你可以在那裏看到放鬆型安全的結果。在編譯時加入2將會在編譯時失敗Set<?>,但對於原始類型Set,它將被成功添加,但它可能會在運行時拋出異常,當您從集合中獲取元素並將其分配給String

不同之處在於,您應該避免在較新的代碼中使用原始類型。你很少會發現你會使用它的地方。您使用原始類型的幾個地方是訪問該類型的static字段,或獲取該類型的Class對象 - 您可以執行Set.class,但不能執行Set<?>.class

+3

任何情況下情況1( *無效的一個*)可用於? – NoobEditor

+2

「Invalid」可以在這種情況下工作:'Set <? super String> s = new HashSet ();'例如 –

+1

通常您指定編譯時安全檢查的泛型。因此,在java 1.5之後,你應該沒有理由指定原始類型。 – noMAD

5

第一個創建Set<?>,這意味着:「一個未知類的通用集合」。您將無法向該集合添加任何內容(空值除外),因爲編譯器不知道其泛型類型是什麼。

第二個創建一個原始非泛型集合,您可以添加任何你想要的。它不提供任何類型安全。

我不明白你爲什麼要使用它們中的任何一個。 Set<String>應該是聲明的類型。

3

第一個使用泛型,第二個使用原始格式Set

第一個使用通配符作爲泛型類型參數。這意味着,「某個特定的未知類型的Set」,所以你不會調用諸如add這樣的方法來獲取一個通用參數,因爲編譯器不知道它確實是哪個特定的類型。它通過在編譯時禁止這種調用來維護類型安全。

原始表單刪除所有泛型並且不提供強類型。您可以添加任何這樣的Set,甚至非String s,這使得下面的代碼不是類型安全:

Set<String> genericSet = new HashSet<String>(); 
Set rawSet = genericSet; 
rawSet.add(1); // That's not a String! 

// Runtime error here. 
for (String s : genericSet) 
{ 
    // Do something here 
} 

這將導致運行時,當Integer1檢索ClassCastExceptionString預期。

保持儘可能多的通用類型信息是可行的。

Set<String> s = HashSet<String>(); 
3

Set<?>告訴編譯器該集合包含特定的類型,但類型是未知的。當您嘗試調用帶有通用參數的方法時,編譯器使用此信息提供錯誤,如add(T)

Set告訴編譯器該集合是一個「原始」類型,其中沒有泛型類型參數。當對象的泛型方法被調用時,編譯器會引發警告而不是錯誤。

爲了將元素添加到沒有警告的集合中,您需要指定變量的通用類型信息。編譯器可以推斷構造函數的類型參數。像這樣:

Set<String> s = new HashSet<>(); 

此信息允許編譯器驗證Set是否以類型安全的方式使用。如果您的代碼在沒有類型安全警告的情況下編譯,並且您沒有使用任何明確的強制轉換,則可以確保在運行時不會生成ClassCastException。如果您使用泛型,但忽略類型安全警告,則可能會看到ClassCastException在源代碼中沒有強制轉換的位置處引發。

相關問題