代码之家  ›  专栏  ›  技术社区  ›  Sajal Dutta

类型安全:未选中的铸件

  •  211
  • Sajal Dutta  · 技术社区  · 16 年前

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

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

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

    9 回复  |  直到 6 年前
        1
  •  222
  •   chelmertz user1604064    7 年前

    好吧,首先,你在浪费新的记忆 HashMap 创建调用。第二行完全忽略了对这个创建的hashmap的引用,这样垃圾收集器就可以使用它了。所以,不要这样做,使用:

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

    其次,编译器抱怨您将对象强制转换为 哈希图 不检查是否是 哈希图 . 但是,即使你要这样做:

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

    你可能仍然会收到这个警告。问题是, getBean 收益率 Object ,所以不知道类型是什么。将其转换为 哈希图 直接不会引起第二种情况的问题(也许在第一种情况下不会有警告,我不知道Java编译器对于Java 5的警告是多么迂腐)。但是,您正在将其转换为 HashMap<String, String> .

    hashmaps实际上是以对象为键并以对象为值的映射, HashMap<Object, Object> 如果你愿意的话。因此,不能保证当您得到bean时,它可以表示为 hashmap<字符串,字符串> 因为你可以 HashMap<Date, Calendar> 因为返回的非泛型表示可以有任何对象。

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

        2
  •  271
  •   Jon Skeet    16 年前

    问题是,强制转换是一个运行时检查——但是由于类型擦除,在运行时,在 HashMap<String,String> HashMap<Foo,Bar> 对于任何其他 Foo Bar .

    使用 @SuppressWarnings("unchecked") 抓住你的鼻子。哦,在爪哇为泛化的仿制药运动:

        3
  •  67
  •   Amarghosh    7 年前

    如上所示,列表不能在 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);
    

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

        4
  •  24
  •   David M. Karr    16 年前

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

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

    @SuppressWarnings (value="unchecked")
    
        5
  •  9
  •   David Nehme    16 年前

    您收到此消息是因为getbean返回一个对象引用,并且您正在将其强制转换为正确的类型。Java 1.5给你一个警告。这就是使用Java 1.5的性质,或者更好地使用这样的代码。弹簧有类型安全型

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

    在它的待办事项列表上。

        6
  •  5
  •   Rabbit    9 年前

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

    例如,如果您试图使用

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

    你可以创建一个这样的新类

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

    然后当你使用

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

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

        7
  •  1
  •   Jeremy    8 年前

    另一个解决方案是,如果你发现自己对同一个对象进行了大量的强制转换,并且你不想乱扔代码 @SupressWarnings("unchecked") ,将创建一个带有注释的方法。这样,您就可以集中演员阵容,并希望减少出错的可能性。

    @SuppressWarnings("unchecked")
    public static List<String> getFooStrings(Map<String, List<String>> ctx) {
        return (List<String>) ctx.get("foos");
    }
    
        8
  •  1
  •   João Neto    6 年前

    避免未选中警告的解决方案:

    class MyMap extends HashMap<String, String> {};
    someMap = (MyMap)getApplicationContext().getBean("someMap");
    
        9
  •  0
  •   Andy    8 年前

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

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

    解决办法

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

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

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

    步骤2: 实例化主映射

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

    步骤3: 迭代临时映射并将值设置到主映射中

     for(Map.Entry<?, ?> entry :myInputObj.entrySet()){
            myInput.put((String)entry.getKey(),entry.getValue()); 
        }
    
    推荐文章