在我的Spring应用程序上下文文件中,我有如下内容:
1 2 3 4
| <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类中,实现看起来像:
1 2
| private Map <String, String > someMap = new HashMap <String, String >();
someMap = (HashMap <String, String >)getApplicationContext (). getBean("someMap"); |
在Eclipse中,我看到一个警告:
类型安全:未选中从对象强制转换为哈希映射
我做错了什么?如何解决该问题?
- 我设计了一个程序来实际检查参数化hashmap的转换,这消除了未选中的转换警告:link我会说这是"正确的"解决方案,但是它的价值是否值得争论。:)
- 相关/重复:如何处理未选中的强制转换警告?
- 如何处理未选中的强制转换警告的可能副本?
问题在于,强制转换是一种运行时检查——但是由于类型擦除,在运行时,对于任何其他Foo和Bar,HashMap和HashMap实际上没有区别。
用@SuppressWarnings("unchecked")按住鼻子。哦,在爪哇为泛化的仿制药运动:
- 我将把Java的泛化泛型放在非类型化的NSMutable上,这感觉像是一个十年的倒退,一周中的任何一天。至少Java正在尝试。
- 确切地。如果您坚持类型检查,则只能使用hashmap<??>这不会删除警告,因为它与不检查泛型类型的类型相同。这不是世界末日,但令人恼火的是,你要么被抓到压制警告,要么就活在警告中。
- @Jonskeet什么是真正的通用?
- @sasq:stackoverflow.com/questions/879855
首先,你在新的HashMap创建调用中浪费了内存。第二行完全忽略了对这个创建的hashmap的引用,这样垃圾收集器就可以使用它了。所以,不要这样做,使用:
1
| private Map <String, String > someMap = (HashMap <String, String >)getApplicationContext (). getBean("someMap"); |
其次,编译器抱怨您在不检查对象是否为HashMap的情况下将对象强制转换为HashMap。但是,即使你要这样做:
1 2 3
| if(getApplicationContext (). getBean("someMap") instanceof HashMap) {
private Map <String, String > someMap = (HashMap <String, String >)getApplicationContext (). getBean("someMap");
} |
你可能仍然会收到这个警告。问题是,getBean返回Object,所以类型未知。将它直接转换为EDCOX1(0),不会引起第二种情况的问题(也可能在第一种情况下不会有警告,我不知道Java编译器对于Java 5的警告是多么迂腐)。但是,您正在将其转换为HashMap。
hashmaps实际上是一种将对象作为键并将对象作为值的映射,如果愿意,可以使用HashMap。因此,不能保证当您得到bean时,它可以表示为HashMap,因为您可以拥有HashMap,因为返回的非泛型表示可以具有任何对象。
如果代码是编译的,并且您可以执行String value = map.get("thisString");,而不会出现任何错误,那么不要担心这个警告。但是,如果映射不完全是字符串值的字符串键,那么您将在运行时得到一个ClassCastException,因为在这种情况下,泛型无法阻止这种情况的发生。
- 这是一段时间以前的事了,但是我在一个强制转换之前正在寻找一个关于类型检查集合的答案,并且您不能在参数化的泛型上实例化。例如,如果(event.getTarget instanceof set)您只能使用?这并不能消除铸造警告。例如,if(event.getTarget instanceof set<?>)
如上述信息所示,该列表不能区分List和List或List。
我已经为类似的问题解决了此错误消息:
1 2
| List <String > strList = (List <String >) someFunction ();
String s = strList. get(0); |
包括以下内容:
1 2
| List <?> strList = (List <?>) someFunction ();
String s = (String) strList. get(0); |
说明:第一个类型转换验证对象是否是列表,而不关心其中包含的类型(因为我们无法在列表级别验证内部类型)。第二个转换现在是必需的,因为编译器只知道列表包含某种对象。这将在访问列表时验证列表中每个对象的类型。
- 你说得对,我的朋友。不用强制转换列表,只需迭代它并强制转换每个元素,警告就不会出现,太棒了。
- 这消除了警告,但我仍然不自信:p
- 是的感觉就像蒙蔽了编译器,但不是运行时:d,所以我看不到它与@suppresswarnings("unchecked")之间的任何区别。
警告就是这样。警告。有时警告无关紧要,有时则不然。它们用于提醒您注意编译器认为可能有问题但可能没有的事情。
在铸造的情况下,在这种情况下,它总是会给出警告。如果您完全确定特定的强制转换是安全的,那么您应该考虑在行之前添加这样的注释(我不确定语法):
1
| @SuppressWarnings (value="unchecked") |
- -1:警告永远不会被接受。或者取消或修复这些警告。在这一刻,你将不得不面对许多警告,而你不会再看到相关的警告。
- 在强制转换参数化的泛型(如map)时,不能真正避免类强制转换警告,因此这是原始问题的最佳答案。
- 这是完美的大卫!
您收到此消息是因为getbean返回一个对象引用,并且您正在将其强制转换为正确的类型。Java 1.5给你一个警告。这就是使用Java 1.5的性质,或者更好地使用这样的代码。弹簧有类型安全型
1
| someMap =getApplicationContext (). getBean<HashMap <String, String >>("someMap"); |
在它的待办事项列表上。
如果您真的想消除警告,您可以做的一件事是创建一个扩展自泛型类的类。
例如,如果您试图使用
1
| private Map <String, String > someMap = new HashMap <String, String >(); |
你可以创建一个这样的新类
1 2 3 4
| public class StringMap extends HashMap <String, String >()
{
// Override constructors
} |
然后当你使用
1
| someMap = (StringMap) getApplicationContext().getBean("someMap"); |
编译器确实知道(不再是通用的)类型是什么,并且不会出现警告。这可能并不总是一个完美的解决方案,有些人可能会认为这种方法破坏了泛型类的目的,但是您仍然在使用来自泛型类的所有相同代码,您只是在编译时声明您要使用的类型。
避免未选中警告的解决方案:
1 2
| class MyMap extends HashMap <String, String > {};
someMap = (MyMap )getApplicationContext (). getBean("someMap"); |
以下代码导致类型安全警告
Map myInput = (Map) myRequest.get();
Workaround
创建一个新的映射对象而不提及参数,因为列表中包含的对象类型未经验证。
步骤1:创建新的临时映射
Map, ?> tempMap = (Map, ?>) myRequest.get();
步骤2:实例化主映射
1
| Map <String, Object > myInput =new HashMap <>(myInputObj. size()); |
步骤3:迭代临时映射并将值设置到主映射中
1 2 3
| for(Map. Entry<?, ?> entry :myInputObj. entrySet()){
myInput. put((String)entry. getKey(),entry. getValue());
} |
另一种解决方案是,如果您发现自己对同一个对象进行了大量的强制转换,并且不想将代码乱扔到@SupressWarnings("unchecked")中,那么就创建一个带有注释的方法。这样可以集中演员表,并希望减少出错的可能性。
1 2 3 4
| @SuppressWarnings ("unchecked")
public static List <String > getFooStrings (Map <String, List <String >> ctx ) {
return (List <String >) ctx. get("foos");
} |