Java通用转换,非直接

时间:2012-01-26 18:38:39

标签: java generics casting classcastexception

我发现Java中的演员有些奇怪,我以前从未见过。 在使用通用方法对其进行编程的情况下,实际上没有完成转换。

测试奇怪的东西。

在HashMap上:

HashMap<String,Object> map = ...
map.put("hello", "World");
System.err.println((Integer)map.get("hello")); //  -----> ClassCastException

在地图包装器上

MapWrap wrap = ...
wrap.put("hello", "World");
System.err.println(wrap.get("hello",Integer.class)); // -----> don't cast, print World (i guess because println receives an Object reference but the cast should be done before that).
System.err.println(wrap.get("hello", Integer.class).toString()); // -----> print World + ClassCastException

方法代码:

private <T> T get(String key, Class<T> c){
    return (T)map.get(key);
}

private Object get(String key){
    return map.get(key);
}

有人知道mechansim是否有名字或知道某事吗?

由于

3 个答案:

答案 0 :(得分:9)

演员:

(T) map.get(key);
由于类型擦除,

根本不做任何事情。方法MapWrap.get()将被删除为:

private Object get(String key, Class<T> c){
    return map.get(key);
}

始终有效。只有在将此方法的结果赋给的地方才会插入到Integer的强制转换,并且因为在第一个MapWrap示例中,您将它传递给需要Object参数的方法,所以不会发生这种情况。 / p>

在第二种情况下,您尝试调用方法Integer.toString(),因此插入到Integer的转换,然后失败。

你已经传入了类对象,正确的做法是“通用演员”:

private <T> T get(String key, Class<T> c){
    return c.cast(map.get(key));
}

答案 1 :(得分:3)

类型参数在编译时被删除。因此,诸如(T)之类的强制转换在可执行文件中变为(Object),因此是您获得的第一个行为。

类型参数仅用于执行编译时键入和类型检查。

但是,在第二行,我认为编译器会生成对Integer.toString()方法的调用,因此需要进行强制转换,因此是异常。

请参阅Java教程中的Type Erasure

答案 2 :(得分:0)

我称之为:“Java中的模板很痛苦”; - )。

该行:

System.err.println(wrap.get("hello",Integer.class));

使用方法println(Object obj),因此没有类型问题,因为没有人实际检查wrap.get的返回对象的类型

在第二种情况下:

System.err.println(wrap.get("hello", Integer.class).toString());

这是被调用的Integer的toString(),你得到了类转换异常。

不幸的是,Chris指出Java正在从模板中删除类型,但记住仍然存在于方法中(可能)