我发现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是否有名字或知道某事吗?
由于
答案 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正在从模板中删除类型,但记住仍然存在于方法中(可能)