2010-07-15 165 views
2
class Response<T> 
{ ... } 

Response response = new Response(); 

上面的代碼編譯。我不明白什麼是暗示。編譯器是否需要'T'的類型規範?例如如下所示:Java泛型 - 類型聲明

Response<String> response = new Response<String>(); 
+0

另請參閱:http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it – polygenelubricants 2010-07-16 08:11:01

回答

6

從技術上講,它應該/應該。但是,爲了向後兼容Java 5,這不會完成,因此不需要通用參數。而且由於無論如何泛型都是通過擦除來實現的,所以無論您是否聲明參數,發出的字節碼都是相同的 - 您錯過了一些編譯時檢查。

(請注意,如果你打電話給你response對象的方法,編譯器會發出警告有關使用「原始類型」,這意味着你在一個非通用的方式使用泛型類,因此它不能)

編輯:關於向後兼容性,這是一種平衡行爲,Sun已經明確犧牲了某些方面以改善/維護他人。打破向後兼容性將是一筆相當大的交易 - 這意味着遷移到最新版本的Java將是一個不平凡的項目,並會在企業內部對升級產生更大的阻力。

這裏的一個重大決定是通過擦除來實現泛型,使得它們是「僅編譯時」構造,生成的字節碼與先前的版本相同。這具有如下優點:例如,在1.5中的java.util.HashMap仍然可以通過1.4編寫的代碼訪問(當然,這個優點也延伸到你自己的類)。然而,有很多觀點,特別是那些習慣於其他語言的泛型的人,他們想要使用類似的技術,這不是最好的決定,並且已經削弱了泛型的有用性。我不打算在這裏斟酌。

至於它是否會破壞編譯器想要執行的檢查;我認爲這不像你想象的那麼糟糕。 是的,您可以編寫代碼,以便編譯器不會執行任何泛型檢查,並且可以故意顛覆預期的語義。然而,編譯時檢查並不意味着某種安全特性,它們僅僅是爲了幫助你,作爲一種靜態分析的形式,它將挑選某些類別的錯誤。如果你顛覆他們,請隨時這樣做。但是如果你正確地編寫泛型類,那麼你會得到你想要的編譯時檢查。

特別是因爲編譯器(可以)給你關於原始類型的警告,所以有一個從1.4到5的清晰升級路徑。升級你的JDK - 你的舊代碼仍然會編譯,儘管有警告。然後使用這些警告追查違規行爲,並在需要時生成舊代碼。在我看來,這比僅僅拒絕編譯舊的(推測是功能性的)代碼要好得多,直到每個語句都添加了適當的泛型。

大多數IDE將允許您對不同警告類型的嚴重程度進行分類,例如,如果您從頭開始開發Java 5應用程序,則可以告訴它將所有原始類型警告視爲完全停止構建錯誤。

+0

Java 5添加了泛型,向後兼容性爲pre-version 5 – 2010-07-15 16:32:31

+0

感謝您回覆Andrzej。我添加了編譯器選項-Xlint:未選中,由Jon在下面提出。似乎這應該是默認設置。我是錯誤的還是爲了向後兼容的努力似乎規避了程序員試圖強加於仿製藥的那種類型? – Bruce 2010-07-15 17:04:48

+0

可以說這應該是默認設置,但我認爲你會遇到同樣的問題 - 一個人一直在使用Java 1.4升級到Java 5,並且突然之間會發出數百條警告(在這種情況下無關緊要)。請參閱我的編輯以瞭解我對向後兼容性的看法,因爲在那裏寫明確的段落會更容易! – 2010-07-16 07:56:02

1

我認爲,通過在底部行中沒有指定模板類,會導致編譯器自動替換類型Object。這並沒有錯,它在執行類型時不是很有效。

+1

實際上它甚至不等同於用''代替,更類似於用''代替具體實例(如果你自己聲明它,這將不合法)。由於泛型不是協變的,*任何*具體類型,甚至是「對象」都會限制某些方法調用。例如,一個通用的方法'addToCollection(Collection c)'只會在您聲明的情況下接受'Collection '的參數,但實際上使用原始類型時,它們將允許任何Collection。 – 2010-07-15 16:15:33

0

這將編譯得很好。如果沒有,你會遇到遺留代碼的問題。例如,由於HashMap現在被聲明爲HashMap<K, V>,您將如何處理聲明(未參數化)散列表的所有代碼?

當您嘗試使用該參數值你只會得到錯誤:

class Response<T> 
{ public T get()... } 

String s= new Reponse().get(); //breaks - or requires a cast 
String s= new Response<String>().get(); 
2

這就是所謂的原始類型。你應該能夠打開警告,讓它對你投訴 - 聽取這些警告。

例如,這裏是我所得到的,當我運行

javac -Xlint Test.java 

與您的代碼(包裝原始類型引用轉換成Test類):

C:\Users\Jon\Test>javac -Xlint Test.java 
Test.java:7: warning: [rawtypes] found raw type: Response 
    Response response = new Response(); 
    ^
    missing type parameters for generic class Response<T> 
    where T is a type-variable: 
    T extends Object declared in class Response 
Test.java:7: warning: [rawtypes] found raw type: Response 
    Response response = new Response(); 
          ^
    missing type parameters for generic class Response<T> 
    where T is a type-variable: 
    T extends Object declared in class Response 
2 warnings 

如果你沒有這些警告,我建議你盡一切努力在你的環境中看到它們。這將取決於您使用的IDE /編譯器,但如果您找不到相關設置,請告訴我們您正在使用哪一個,我確信有人能夠爲您找到它。

請參閱Angelika Langer的Java Generics FAQ的raw types section瞭解更多信息。

+0

感謝Jon,我更新了NetBeans以使用-Xlint:未選中。您提供的鏈接非常有幫助。 – Bruce 2010-07-15 17:05:34