2016-05-30 75 views
0

項目23(不要使用新代碼的原始類型)有效的Java中聲稱,在Java代碼中使用原始類型總是危險原始類型總是不好?

例如,它聲稱,下面的方法是危險和不安全

// Use of raw type for unknown element type - don't do this! 
static int numElementsInCommon(Set s1, Set s2) { 
    int result = 0; 
    for (Object o1 : s1) 
     if (s2.contains(o1)) 
      result++; 
    return result; 
} 

儘管我可以看到在s1和s2上執行任何類型的寫操作或類轉換操作都會導致各種異常,但我不明白爲什麼上述方法不安全。作者Joshua Bloch繼續推薦以下方法。

// Unbounded wildcard type - typesafe and flexible 
static int numElementsInCommon(Set<?> s1, Set<?> s2){ 
    int result = 0; 
    for (Object o1 : s1) 
    if (s2.contains(o1)) 
     result++; 
    return result; 
} 

換句話說,如果一個方法只使用Object.Class的方法和沒有做任何修改所傳遞的參數,爲什麼這樣做不好?

+3

在很久以前,在泛型之前,人們會在當天的集合中混合**類型(即'Hashtable'和'Vector',它們不是那些日子裏的集合)。這導致了諸如'[0,「abc」,Date]'這樣的事情,因爲Java允許你創建自己的數據類型。使用'Set ',您可以保證一致的元素類型。 –

+0

當然。我的問題是,原始類型不安全的情況下,只讀方法或操作只涉及暴露的方法** Object.Class ** –

+0

不,它們不是。在運行時,所有類型都是原始的,並且它們與推薦的通配符方法完全相同。但是這種方法會讓編譯器檢查你實際上沒有做這些「安全的事情」。如果沒有通配符,如果您不小心將其添加到您的套件中,則不會收到錯誤消息。因此,如果您知道它,請使用通用類型;如果不知道,請使用通配符。不要使用原始類型。 – Thilo

回答

2

從某種意義上說,它阻止編譯器對類型檢查代碼進行類型檢查是不好的。

當然,你可以在沒有它的情況下編寫出好而安全的代碼。人們每天都用Perl和Javascript來做。即使在Java中,使用原始類型和在運行時使用類型集合也沒有區別。但是爲了儘可能多地進行編譯器檢查,有一點可以說。

因此,採用類似於您的示例的方法,請使用通配符類型(Set<?>)而不是原始類型。這樣,如果你確實寫了「危險」代碼,如s1.addAll(s2);,編譯器會向你大喊。

+0

有道理。我很驚訝地發現界面上的捕獲限制在孩子班級中沒有實施。例如,請參閱https://gist.github.com/dsKarthick/e6b1b62c70f3722b13d9047aa338b8c2。 –

+0

我想你會得到一個關於子類中原始類型的編譯器警告。如果你使用類型,他們必須匹配父界面。 – Thilo

+0

甚至允許您在子類(或Java中的任何位置)上使用原始類型的原因是與Java5之前的舊代碼的向後兼容性。但是,如果您使用類型,則會正確執行。 – Thilo