2011-11-04 50 views
3

據我所知,泛型僅在編譯時有用。自Java5 +鑽石操作員開始泛型集合的方法

因此,可以聲明:

private Set set = new HashSet<String>(); 

,然後在這個字符串HashSet的,狗或任何添加到組,沒有任何問題,因爲沒有在像陣列運行任何檢查( ArrayStoreException信息...)(但你可能當您使用集有一個像classcast問題...

所以,我想說的是,我們通常實例化泛型集合那樣:

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

我的問題是,爲什麼我們把HashSet的類型,因爲只有變量的引用類型是非常重要的(我認爲)。

我的意思是,我們可以簡單的寫:

Set<String> set = new HashSet(); 

而且它的工作完全一樣的吧? 那麼,爲什麼我們通常在實例化過程中寫入類型呢? (這不是強制性的)


編輯

我知道「鑽石經營者」的類型推斷,但是爲什麼我們甚至需要它!因爲類型推斷已經在工作了!

以下代碼:

  Set<String> set = new HashSet(); 
      set.add("Test add a string 1"); 
      set.add("Test add a string 2"); 
      for (String s : set) { 
        System.out.println(s); 
      } 

產生輸出:

測試添加字符串1 測試添加字符串2

測試它自己 http://ideone.com/vuiCE

所以,現在你說說類型推斷作爲Java7的功能,但它已經爲我工作...

隨着java7我將不得不更換我的

  Set<String> set = new HashSet(); 

通過

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

對於做同樣的事情,它還有2個額外的字符嗎? (?除非仿製藥不僅與Java7編譯的時候我不知道)

+0

在Java 7的這個方向取得一些進展:http://download.oracle.com/javase/7/docs/technotes/guides/language/type-in​​ference-generic-instance-creation.html。 – rodrigoap

回答

1

雖然Java目前擦除泛型類型的信息,他們一直十分小心設計語言和庫,使其在未來的加回滿泛型類型信息(所謂的物化)是可能的。任何正確書面通用代碼(即沒有任何javac警告)將經受這種語言更改。在你的例子中,鑽石版本是未來的證明;原始版本不是 - 它當然仍然必須編譯,但它會在運行時拋出類型轉換異常。

然而,這個未來的兼容性完全是一種妄想。擦除將永遠留在我們身邊。如果引入完全實現,可以肯定地說幾乎所有非平凡的泛型代碼都會中斷,因爲每個人都在編寫不正確的泛型代碼。

這不是我們的錯。爪哇迫使我們去。它給了我們廢話刪除,我們別無選擇,只能繞過它來實施的東西。我們的代碼充滿了對擦除細節知識的依賴。

JDK是最有罪的。 JDK API經過精心設計以保留物化特性;然而,這些實現取決於擦除。如果Java添加了具體化,則必須重寫這些JDK代碼。如果Java團隊責怪我們編寫不正確的代碼,而他們必須自己做同樣的事情,那麼Java團隊將非常虛僞。考慮到無需重寫而無法生存的代碼量,我們可以放心地說,Java永遠不會添加具體化,只要它保持向後兼容性的承諾。

在這種情況下,是啊,什麼的。關於Set<String> set = new HashSet()沒有什麼可怕的。我個人總是添加<>以避免警告。 (實際上,只要有可能,我會盡量讓我的代碼具有通用性,就像我說的那樣,這是一種妄想行爲)

在你的例子中,推理是微不足道的。可能有更復雜的情況,其中<>推斷不是那麼簡單,它的類型檢查可能是有用的,這是原始版本缺乏。

class Foo<T> 
{ 
    Foo(Class<T> clazz){} 
} 

Foo<String> foo1 = new Foo(Integer.class); // compiles (wrongly) 

Foo<String> foo2 = new Foo<>(Integer.class); // does not compile 
+0

謝謝。以系統屬性-Druntime.generics = true或類似的東西爲例,將「物化作爲選項」很好,讓選擇讓任何人做他想做的事情...... –

3

你在最後的建議是類型推斷,並已在Java 7中通過所謂的鑽石經營者介紹:

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

所以是的,這可能從一開始就在那裏。但是,這是Java的,它通常需要幾十年獲得批准的新的語言特性(< - 略帶誇張)

4

而且它的工作完全一樣的吧?

在運行時:

在編譯時:沒有

您的代碼將被賦予含有任意對象一組,給一個變量存儲包含字符串這是壞集,將在由類型皺起眉頭-checker。

當您編寫new HashSet()您正在使用raw type。我指的是這個問題,把它的意思,爲什麼應該避免:


在一般情況下,你可能會說這樣的:

Set<String> set = new HashSet(); 

不遠離

HashSet tmp = new HashSet(); 
... 
Set<String> set = tmp; 

這又是不遠處

HashSet tmp = new HashSet(); 
tmp.add(7); 
... 
Set<String> set = tmp; 

仍然編譯,但不利於一千個理由:)


Java 7的讓你寫

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

雖然,它告訴編譯器推斷之間的類型< ... >

文檔的 「金剛石運算符」:

+0

我真的不明白爲什麼將一個對象設置爲一個字符串集變量是不好的,因爲它正是我們在運行時得到的,而且在編譯時它是完全合法的(檢查自己) –

+0

它在編譯時不是*完美*合法時間;-)使用默認的編譯器設置,會得到一個令人討厭的警告(出於很好的理由!)。一個'HashSet'可以包含一個'Integer'。如果將一個包含「整數」的集合賦值給「集合」,會發生什麼? – aioobe

+0

警告並不意味着它是非法的,因爲遺留代碼就是這樣!這是完全合法的! –

0

Java 7個的地址對 類實例創建表達式添加了有限類型推斷。如果參數化類型需要爲構造函數 以及參數化類型< T1,T2 ...明確聲明的 TN>該構造是顯而易見的上下文,則該參數 類型構造函數可被用空集的類型 參數代替:<>。所述<>構造是合法的構建當 OB JECT並且或者將其分配給一個變量,或使當它作爲 一個參數來使用。

詳情:click here

0

其實這是不需要的。 如果鍵入

Set<String> s = new HashSet(); 

代碼編譯,我們得到了它,我們可以用Xlint檢查警告。

Note: filetest.java uses unchecked or unsafe operations. 
Note: Recompile with -Xlint:unchecked for details. 

然後,如果我們嘗試添加一個整數值,例如我們得到一個編譯錯誤。

+0

是的,這正是我的意思,我們可以做到這一點,它的工作原理爲什麼做另一件事或發明一個新的「鑽石操作員」。對於類型推斷,他們應該刪除該警告...... –

+1

@SebastienLorber這實際上是一個很好的問題......爲什麼首先要有鑽石操作員?向後兼容?我沒有考慮過,真的。 –