2013-06-03 40 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的错误。

顺便说一句,你应该在施放时发出警告。忽略警告可能会产生后果......