types安全:未经检查的投射

在我的Spring应用程序上下文文件中,我有这样的:

<util:map id="someMap" map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.String"> <entry key="some_key" value="some value" /> <entry key="some_key_2" value="some value" /> </util:map> 

在java类中,实现如下所示:

 private Map<String, String> someMap = new HashMap<String, String>(); someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap"); 

在Eclipse中,我看到一个警告,说:

types安全性:取消勾选从Object到HashMap

我做错了什么? 我如何解决这个问题?

那么首先,你正在用新的HashMap创build调用来浪费内存。 你的第二行完全忽略了对这个创build的hashmap的引用,使得它可以被垃圾收集器使用。 所以,不要这样做,使用:

 private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap"); 

其次,编译器抱怨说你把对象转换成HashMap而不检查它是否是一个HashMap 。 但是,即使你这样做:

 if(getApplicationContext().getBean("someMap") instanceof HashMap) { private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap"); } 

你可能仍然会得到这个警告。 问题是, getBean返回Object ,所以不知道types是什么。 直接将它转换成HashMap不会导致第二种情况的问题(也许在第一种情况下可能不会有警告,我不确定Java编译器对于Java 5的警告是多么迂腐)。 但是,您将它转换为HashMap<String, String>

HashMap实际上是一个将对象作为关键字并将对象作为值的映射,如果您愿意,可以使用HashMap<Object, Object> 。 因此,当你得到你的bean的时候,可以用HashMap<String, String>因为你可以使用HashMap<Date, Calendar>因为返回的非generics表示可以有任何对象。

如果代码编译,并且可以执行String value = map.get("thisString"); 没有任何错误,不要担心这个警告。 但是,如果映射不是完全由string键值到string值,那么在运行时会得到一个ClassCastException ,因为在这种情况下generics不能阻止这种情况的发生。

问题是cast是一个运行时检查 – 但是由于types擦除,在运行时HashMap<Foo,Bar>对于任何其他FooBar HashMap<String,String>HashMap<Foo,Bar>实际上没有区别。

使用@SuppressWarnings("unchecked")并保持你的鼻子。 哦,在Java中为泛化generics运动

如上面的消息所示,列表不能区分List<Object>List<String>List<Integer>

我已经解决了类似问题的这个错误消息:

 List<String> strList = (List<String>) someFunction(); String s = strList.get(0); 

具体如下:

 List<?> strList = (List<?>) someFunction(); String s = (String) strList.get(0); 

说明:第一种types转换validation对象是一个List,而不关心内部types(因为我们无法validationList级别的内部types)。 现在需要第二次转换,因为编译器只知道List包含某种对象。 这将validationList中每个对象在访问时的types。

警告就是这样。 一个警告。 有时警告是不相关的,有时候不是。 他们习惯于把你的注意力放在编译器认为可能是问题的东西上,但可能不是。

在演员的情况下,在这种情况下总会发出警告。 如果你完全确定特定的演员阵容是安全的,那么你应该考虑在这一行之前添加一个像这样的注解(我不确定语法):

 @SuppressWarnings (value="unchecked") 

您正在收到此消息,因为getBean返回一个Object引用,并将其转换为正确的types。 Java 1.5给你一个警告。 使用Java 1.5或更高版本的代码就是这样工作的。 spring有types安全的版本

 someMap=getApplicationContext().getBean<HashMap<String, String>>("someMap"); 

在待办事项列表中。

如果你真的想摆脱这些警告,你可以做的一件事是创build一个从generics类扩展的类。

例如,如果你正在尝试使用

 private Map<String, String> someMap = new HashMap<String, String>(); 

你可以像这样创build一个新的类

 public class StringMap extends HashMap<String, String>() { // Override constructors } 

那么当你使用

 someMap = (StringMap) getApplicationContext().getBean("someMap"); 

编译器知道什么(不再generics)types,并且不会有任何警告。 这可能并不总是完美的解决scheme,有些人可能会认为这种做法违背了generics类的目的,但是您仍然使用generics类中所有相同的代码,只是在编译时声明了什么types你想使用。

另一个解决scheme,如果你发现自己投了很多同样的对象,而且你不想用@SupressWarnings("unchecked")你的代码, @SupressWarnings("unchecked")就是创build一个带注释的方法。 这样你就可以集中演员阵容,并希望减less错误的可能性。

 @SuppressWarnings("unchecked") public static List<String> getFooStrings(Map<String, List<String>> ctx) { return (List<String>) ctx.get("foos"); } 

以下代码会导致types安全警告

Map<String, Object> myInput = (Map<String, Object>) myRequest.get();

解决方法

创build一个新的Map对象,而不提及参数,因为列表中的对象types没有被validation。

第1步:创build一个新的临时地图

Map<?, ?> tempMap = (Map<?, ?>) myRequest.get();

第2步:实例化主Map

 Map<String, Object> myInput=new HashMap<>(myInputObj.size()); 

步骤3:迭代临时地图并将值设置为主地图

  for(Map.Entry<?, ?> entry :myInputObj.entrySet()){ myInput.put((String)entry.getKey(),entry.getValue()); }