307

在我的 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 中,我看到一条警告说:

类型安全:从 Object 到 HashMap<String,String> 的未经检查的强制转换

什么地方出了错?

4

10 回答 10

358

HashMap<String,String>问题是强制转换是运行时检查 - 但由于类型擦除,在运行时实际上 a和HashMap<Foo,Bar>对于任何其他的Foo和没有区别Bar

使用@SuppressWarnings("unchecked")并握住你的鼻子。哦,还有 Java 中的物化泛型运动 :)

于 2008-11-04T17:09:19.927 回答
278

嗯,首先,你在用 new HashMapcreation 调用浪费内存。您的第二行完全忽略了对这个创建的 hashmap 的引用,使其可供垃圾收集器使用。所以,不要那样做,使用:

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

其次,编译器抱怨您将对象转换为 aHashMap而没有检查它是否是 a 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 时它可以表示为 aHashMap<String, String>因为你可以有HashMap<Date, Calendar>,因为返回的非泛型表示可以有任何对象。

如果代码编译,并且您可以在String value = map.get("thisString");没有任何错误的情况下执行,请不要担心此警告。但是,如果映射不完全是字符串值的字符串键,您将ClassCastException在运行时得到 a,因为在这种情况下泛型无法阻止这种情况发生。

于 2008-11-04T16:44:07.763 回答
109

如上面的消息所示,列表无法区分 aList<Object>和 aList<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 包含某种对象。这将在访问列表时验证列表中每个对象的类型。

于 2012-11-14T21:46:20.857 回答
35

警告就是这样。一个警告。有时警告是无关紧要的,有时则不是。它们用于提醒您注意编译器认为可能是问题但可能不是问题的事情。

在强制转换的情况下,它总是会在这种情况下发出警告。如果您绝对确定特定演员表是安全的,那么您应该考虑在该行之前添加这样的注释(我不确定语法):

@SuppressWarnings (value="unchecked")
于 2008-11-04T16:44:24.970 回答
9

您收到此消息是因为 getBean 返回一个 Object 引用,并且您正在将其转换为正确的类型。Java 1.5 给你一个警告。这就是使用 Java 1.5 或更好的代码来运行这样的代码的本质。Spring 有类型安全的版本

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

在它的待办事项清单上。

于 2008-11-04T16:44:59.460 回答
6

如果您真的想摆脱警告,您可以做的一件事是创建一个从泛型类扩展的类。

例如,如果您尝试使用

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

您可以像这样创建一个新类

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

然后当你使用

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

编译器确实知道(不再是通用的)类型是什么,并且不会发出警告。这可能并不总是完美的解决方案,有些人可能会认为这种方式违背了泛型类的目的,但是您仍然在重用泛型类中的所有相同代码,您只是在编译时声明什么类型你想用。

于 2016-04-13T15:55:31.927 回答
3

下面的代码导致类型安全警告

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

解决方法

创建一个新的地图对象而不提及参数,因为未验证列表中包含的对象类型。

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

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

第二步:实例化主地图

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

第 3 步:迭代临时 Map 并将值设置到主 Map

 for(Map.Entry<?, ?> entry :myInputObj.entrySet()){
        myInput.put((String)entry.getKey(),entry.getValue()); 
    }
于 2016-12-16T14:23:25.227 回答
3

避免未经检查的警告的解决方案:

class MyMap extends HashMap<String, String> {};
someMap = (MyMap)getApplicationContext().getBean("someMap");
于 2018-08-28T15:13:34.890 回答
2

另一种解决方案是,如果您发现自己经常投射相同的对象并且不想在代码中乱扔@SupressWarnings("unchecked"), 将创建一个带有注释的方法。这样你就可以集中演员表,并希望减少出错的可能性。

@SuppressWarnings("unchecked")
public static List<String> getFooStrings(Map<String, List<String>> ctx) {
    return (List<String>) ctx.get("foos");
}
于 2016-10-20T19:25:17.597 回答
2

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

这里 :

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;
    }
}

豆子注入:

@Autowired
@Qualifier("someMap")
Map<String, String> someMap;
于 2019-08-12T14:02:22.150 回答