在我的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中,我看到一条警告:
类型安全:取消选中从对象转换为HashMap
我做错了什么?我该如何解决这个问题?
答案 0 :(得分:277)
问题是强制转换是运行时检查 - 但是由于类型擦除,在运行时,对于任何其他HashMap<String,String>
和{{HashMap<Foo,Bar>
和Foo
之间实际上没有区别1}}。
使用Bar
并捏住鼻子。哦,以及Java中的具体化泛型的竞选活动:)
答案 1 :(得分:231)
嗯,首先,你正在通过新的HashMap
创建调用浪费记忆力。您的第二行完全忽略了对此创建的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
,因此不知道类型是什么。直接将它转换为HashMap
不会导致第二种情况出现问题(也许在第一种情况下不会出现警告,我不确定Java编译器对Java 5的警告有多迂腐)。但是,您要将其转换为HashMap<String, String>
。
HashMaps实际上是一个地图,它将一个对象作为一个键,并将一个对象作为一个值HashMap<Object, Object>
,如果你愿意的话。因此,无法保证当您获取bean时它可以表示为HashMap<String, String>
,因为您可以拥有HashMap<Date, Calendar>
,因为返回的非泛型表示可以包含任何对象。
如果代码编译,并且您可以执行String value = map.get("thisString");
而没有任何错误,请不要担心此警告。但是如果映射不完全是字符串键的字符串键,那么在运行时会得到ClassCastException
,因为在这种情况下泛型不能阻止这种情况发生。
答案 2 :(得分:73)
如上面的消息所示,无法区分列表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);
说明:第一个类型转换验证对象是否为List而不关心其中的类型(因为我们无法在List级别验证内部类型)。现在需要进行第二次转换,因为编译器只知道List包含某种对象。这将在访问列表时验证列表中每个对象的类型。
答案 3 :(得分:26)
警告就是这样。一个警告。有时警告是无关紧要的,有时它们不是。它们习惯于引起你注意编译器认为可能存在问题的东西,但可能不是。
在演员阵容的情况下,在这种情况下总是会发出警告。如果您完全确定某个特定的强制转换是安全的,那么您应该考虑在该行之前添加这样的注释(我不确定语法):
@SuppressWarnings (value="unchecked")
答案 4 :(得分:9)
您收到此消息是因为getBean返回一个Object引用,并且您将其转换为正确的类型。 Java 1.5会给出警告。这就是使用Java 1.5或更高版本的代码的性质。 Spring有类型安全版本
someMap=getApplicationContext().getBean<HashMap<String, String>>("someMap");
在其待办事项清单上。
答案 5 :(得分:5)
如果你真的想摆脱警告,你可以做的一件事是创建一个从泛型类扩展的类。
例如,如果您尝试使用
private Map<String, String> someMap = new HashMap<String, String>();
您可以创建一个类似
的新类public class StringMap extends HashMap<String, String>()
{
// Override constructors
}
然后当你使用
someMap = (StringMap) getApplicationContext().getBean("someMap");
编译器知道(不再是通用)类型是什么,并且没有警告。这可能并不总是完美的解决方案,有些人可能会认为这种方法违背了泛型类的目的,但你仍然在重复使用泛型类中的所有相同代码,你只需要声明编译你想要使用的类型。
答案 6 :(得分:1)
Another solution, if you find yourself casting the same object a lot and you don't want to litter your code with @SupressWarnings("unchecked")
, would be to create a method with the annotation. This way you're centralizing the cast, and hopefully reducing the possibility for error.
@SuppressWarnings("unchecked")
public static List<String> getFooStrings(Map<String, List<String>> ctx) {
return (List<String>) ctx.get("foos");
}
答案 7 :(得分:1)
以下代码会导致类型安全警告
Map<String, Object> myInput = (Map<String, Object>) myRequest.get();
解决方法强>
创建一个新的Map Object而不提及参数,因为列表中保存的对象类型未经验证。
第1步: 创建新的临时地图
Map<?, ?> tempMap = (Map<?, ?>) myRequest.get();
第2步: 实例化主地图
Map<String, Object> myInput=new HashMap<>(myInputObj.size());
第3步: 迭代临时地图并将值设置为主地图
for(Map.Entry<?, ?> entry :myInputObj.entrySet()){
myInput.put((String)entry.getKey(),entry.getValue());
}
答案 8 :(得分:1)
避免未经检查的警告的解决方案:
class MyMap extends HashMap<String, String> {};
someMap = (MyMap)getApplicationContext().getBean("someMap");
答案 9 :(得分:0)
我做错了什么?我该如何解决该问题?
这里:
Map<String,String> someMap = (Map<String,String>)getApplicationContext().getBean("someMap");
您使用的是我们通常不希望使用的旧方法,因为该方法返回Object
:
Object getBean(String name) throws BeansException;
倾向于从bean工厂获取(对于单例)/创建(对于原型)bean的方法是:
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
使用它,例如:
Map<String,String> someMap = app.getBean(Map.class,"someMap");
将编译,但仍带有未检查的转换警告,因为所有Map
对象不一定都是Map<String, String>
对象。
但是<T> T getBean(String name, Class<T> requiredType) throws BeansException;
在诸如泛型集合之类的bean泛型类中还不够,因为它需要指定多个类作为参数:集合类型及其泛型。
在这种情况下,总的来说,更好的方法不是直接使用BeanFactory
方法,而是让框架注入Bean。
bean声明:
@Configuration
public class MyConfiguration{
@Bean
public Map<String, String> someMap() {
Map<String, String> someMap = new HashMap();
someMap.put("some_key", "some value");
someMap.put("some_key_2", "some value");
return someMap;
}
}
bean注入:
@Autowired
@Qualifier("someMap")
Map<String, String> someMap;