Java 类型安全:未选中强制类型转换

Java 类型安全:未选中强制类型转换,java,spring,type-safety,unchecked,Java,Spring,Type Safety,Unchecked,在我的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"

在我的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");
私有映射someMap=newhashmap();
someMap=(HashMap)getApplicationContext().getBean(“someMap”);
在Eclipse中,我看到一条警告,上面写着:

类型安全:未选中从对象到哈希映射的强制转换


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

首先,新的
HashMap
创建调用浪费了内存。您的第二行完全忽略了对这个创建的hashmap的引用,从而使垃圾收集器可以使用它。因此,不要这样做,使用:

private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");
您可能仍然会收到此警告。问题是,
getBean
返回
Object
,因此不知道类型是什么。直接将其转换为
HashMap
不会导致第二种情况出现问题(第一种情况下可能不会出现警告,我不确定Java编译器对Java 5的警告有多迂腐)。但是,您正在将其转换为
HashMap

HashMaps实际上是将对象作为键并将对象作为值的映射,
HashMap
(如果愿意)。因此,无法保证当您获得bean时,它可以表示为
HashMap
,因为您可以拥有
HashMap
,因为返回的非泛型表示可以有任何对象


如果代码已编译,您可以执行
String value=map.get(“thisString”)没有任何错误,不要担心此警告。但是,如果映射不是完全由字符串键到字符串值组成,那么在运行时将得到一个
ClassCastException
,因为泛型无法阻止这种情况发生。

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

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

@SuppressWarnings (value="unchecked")

您之所以收到此消息,是因为getBean返回一个对象引用,并且您正在将其强制转换为正确的类型。Java1.5给了您一个警告。这就是将Java1.5或更高版本与这样的代码一起使用的本质。Spring具有类型安全版本

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

问题在于强制转换是一种运行时检查——但由于类型擦除,在运行时,任何其他
Foo
Bar
HashMap
HashMap
之间实际上没有区别


使用
@SuppressWarnings(“未选中”)
并按住鼻子。哦,还有Java中具体化泛型的活动:)

正如上面的消息所指出的,列表不能在
列表
列表
列表
之间进行区分

我已解决了类似问题的此错误消息:

List<String> strList = (List<String>) someFunction();
String s = strList.get(0);
List strList=(List)someFunction();
字符串s=strList.get(0);
以下是:

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

说明:第一次类型转换验证对象是否为列表,而不考虑其中包含的类型(因为我们无法在列表级别验证内部类型)。现在需要进行第二次转换,因为编译器只知道列表包含某种类型的对象。这将在访问列表中的每个对象时验证其类型。

如果您确实想消除警告,可以做的一件事是创建一个从泛型类扩展而来的类

例如,如果您试图使用

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

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

另一种解决方案,如果您发现自己多次强制转换同一对象,并且不想在代码中乱扔
@supersswarnings(“unchecked”)
,那么就创建一个带有注释的方法。通过这种方式,您可以集中演员阵容,并希望减少出错的可能性

@SuppressWarnings("unchecked")
public static List<String> getFooStrings(Map<String, List<String>> ctx) {
    return (List<String>) ctx.get("foos");
}
@SuppressWarnings(“未选中”)
公共静态列表getFooStrings(映射ctx){
返回(列表)ctx.get(“foos”);
}

以下代码导致类型安全警告

Map myInput=(Map)myRequest.get()

解决方法

创建一个新的映射对象而不提及参数,因为列表中保存的对象类型未经验证

步骤1:创建新的临时映射

Map tempMap=(Map)myRequest.get()

步骤2:实例化主映射

Map<String, Object> myInput=new HashMap<>(myInputObj.size());
 for(Map.Entry<?, ?> entry :myInputObj.entrySet()){
        myInput.put((String)entry.getKey(),entry.getValue()); 
    }
Map myInput=newhashmap(myInputObj.size());
步骤3:迭代临时映射并将值设置到主映射中

Map<String, Object> myInput=new HashMap<>(myInputObj.size());
 for(Map.Entry<?, ?> entry :myInputObj.entrySet()){
        myInput.put((String)entry.getKey(),entry.getValue()); 
    }
for(Map.Entry:myInputObj.entrySet()){
myInput.put((字符串)entry.getKey(),entry.getValue());
}

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

class MyMap extends HashMap<String, String> {};
someMap = (MyMap)getApplicationContext().getBean("someMap");
classmymap扩展了HashMap{};
someMap=(MyMap)getApplicationContext().getBean(“someMap”);
我做错了什么?我如何解决这个问题

在这里:

Map someMap=(Map)getApplicationContext().getBean(“someMap”)

您使用的是我们通常不想使用的遗留方法,因为该方法返回
对象

Object getBean(String name) throws BeansException;
有利于获取(对于singleton)/创建(对于prototype)bean fr的方法
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Map<String,String> someMap = app.getBean(Map.class,"someMap");
@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;