2013-06-03 64 views
3

這是我遇到的一個縮小范例。Java泛型::未能提供類型安全性?

看看下面的代碼:

class Holder<T> { 
    private T t; 
    public Holder(T t) { 
     this.t = t; 
    } 
    public T getValue() { 
     return t; 
    } 
} 

public class FooMain { 

    private static Object newHolder() { 
     return new Holder<Integer>(3); 
    } 

    public static void main(String args[]) { 
     Holder<String> hs = (Holder<String>) newHolder(); // line-18 
     String s = hs.getValue();       // line-19 
    } 
} 

什麼嚇到我的是,必然ClassCastException被扔在線19而不是線18

因此,在您的代碼中有一個類型爲Holder<String>的對象不足以保證getValue將返回String。你還必須研究這個對象是如何構造的!

我知道Type Erasure在這裏扮演一個角色,但我不確定上面的影響有多廣。在我的特殊情況下,newHolder-相應的方法在外部庫中定義並返回java.lang.Object,所以我必須執行這些轉換。

+0

您假定由外部庫方法Object newHolder()返回的對象將是Holder ,因此,儘管有編譯器警告,但是明確地轉換了結果。這意味着你正在告訴編譯器 - *我知道的更好。*但是你的假設是錯誤的。在作出這樣的決定時,你不應該做出假設,而應該百分之百確定。 –

+0

相關:http://stackoverflow.com/a/12209857/697449 –

回答

2

編譯時會發出警告,表示您正在執行強制轉換,這意味着編譯器無法保證類型安全。當你製作這些演員並獲得這些警告時,你基本上是靠自己的。由於泛型是在Java中使用擦除來實現的,所以泛型類型信息在運行時會消失 - 它純粹是一個編譯時構造,因此如果您繞過這個過程,運行時可能會在以後才知道您執行了無效轉換。

+0

不僅僅是任何強制轉換,而是一個* unchecked *強制轉換,這意味着錯誤的泛型類型將不會快速失敗並帶有ClassCastException。 –

2

仿製藥是編譯時間工具來檢查類型安全。在運行時沒有驗證,從type erasure。這就是爲什麼你從Integer中得到一個String的錯誤。

順便說一句,你應該在施放時發出警告。忽略警告可能會產生後果......