首页 文章

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

提问于
浏览
208

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

Type safety: Unchecked cast from Object to HashMap

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

9 回答

  • 23

    好吧,首先,你正在用新的 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 ,因为在这种情况下,泛型不能阻止这种情况发生 .

  • 5

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

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

  • 9

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

  • 1

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

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

    @SuppressWarnings (value="unchecked")
    
  • 66

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

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

    在它的待办事项清单上 .

  • 267

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

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

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

    您可以创建这样的新类

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

    然后当你使用

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

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

  • 0

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

    @SuppressWarnings("unchecked")
    public static List<String> getFooStrings(Map<String, List<String>> ctx) {
        return (List<String>) ctx.get("foos");
    }
    
  • 0

    Below code causes Type safety Warning

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

    解决方法

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

    Step 1: 创建一个新的临时 Map

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

    Step 2: 实例化主 Map

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

    Step 3: 迭代临时Map并将值设置到主Map中

    for(Map.Entry<?, ?> entry :myInputObj.entrySet()){
            myInput.put((String)entry.getKey(),entry.getValue()); 
        }
    
  • 220

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

    class MyMap extends HashMap<String, String> {};
    someMap = (MyMap)getApplicationContext().getBean("someMap");
    

相关问题