类型安全:未经检查的演员

319961 观看

10回复

4168 作者的声誉

在我的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的未选中转换

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

作者: DragonBorn 的来源 发布者: 2008 年 11 月 4 日

回应 (10)


235

22620 作者的声誉

决定

好吧,首先,你正在用新的HashMap创作电话浪费记忆力。您的第二行完全忽略了对此创建的hashmap的引用,使其可用于垃圾收集器。所以,不要这样做,使用:

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

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

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

作者: MetroidFan2002 发布者: 04.11.2008 04:44

27

6570 作者的声誉

警告就是这样。一个警告。有时警告是无关紧要的,有时它们不是。它们习惯于引起你注意编译器认为可能存在问题的东西,但可能不是。

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

@SuppressWarnings (value="unchecked")
作者: David M. Karr 发布者: 04.11.2008 04:44

9

18319 作者的声誉

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

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

在它的待办事项清单上。

作者: David Nehme 发布者: 04.11.2008 04:44

290

1124078 作者的声誉

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

使用@SuppressWarnings("unchecked")并抓住你的鼻子。哦,Java中的具体化泛型运动:)

作者: Jon Skeet 发布者: 04.11.2008 05:09

77

786 作者的声誉

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

作者: Larry Landry 发布者: 14.11.2012 09:46

5

70 作者的声誉

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

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

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

您可以创建这样的新类

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

然后当你使用

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

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

作者: Rabbit 发布者: 13.04.2016 03:55

1

19572 作者的声誉

另一个解决方案是,如果你发现自己经常使用相同的对象并且不想丢弃代码@SupressWarnings("unchecked"),那么就是创建一个带注释的方法。这样你就可以集中演员阵容,并希望减少错误的可能性。

@SuppressWarnings("unchecked")
public static List<String> getFooStrings(Map<String, List<String>> ctx) {
    return (List<String>) ctx.get("foos");
}
作者: Jeremy 发布者: 20.10.2016 07:25

1

646 作者的声誉

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

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

解决方法

创建新的Map对象而不提及参数,因为未验证列表中保留的对象类型。

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

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

第2步:实例化主地图

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

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

 for(Map.Entry<?, ?> entry :myInputObj.entrySet()){
        myInput.put((String)entry.getKey(),entry.getValue()); 
    }
作者: Andy 发布者: 16.12.2016 02:23

2

36 作者的声誉

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

class MyMap extends HashMap<String, String> {};
someMap = (MyMap)getApplicationContext().getBean("someMap");
作者: ochakov 发布者: 28.08.2018 03:13

0

77582 作者的声誉

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

这里 :

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;
作者: davidxxx 发布者: 12.08.2019 02:02
32x32