如何解决未经检查的强制转换警告?

新手上路,请多包涵

Eclipse 给我以下形式的警告:

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

这是来自对我无法控制返回对象的 API 的调用:

 HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
  HashMap<String, String> theHash = (HashMap<String, String>)session.getAttribute("attributeKey");
  return theHash;
}

如果可能的话,我想避免 Eclipse 警告,因为理论上它们至少表明存在潜在的代码问题。不过,我还没有找到消除这个问题的好方法。我可以将涉及的单行单独提取到一个方法中,并将 @SuppressWarnings("unchecked") 添加到该方法中,从而限制了我忽略警告的代码块的影响。有更好的选择吗?我不想在 Eclipse 中关闭这些警告。

在我来到代码之前,它更简单,但仍然引发了警告:

 HashMap getItems(javax.servlet.http.HttpSession session) {
  HashMap theHash = (HashMap)session.getAttribute("attributeKey");
  return theHash;
}

当您尝试使用您会收到警告的哈希时,问题出在其他地方:

 HashMap items = getItems(session);
items.put("this", "that");

Type safety: The method put(Object, Object) belongs to the raw type HashMap.  References to generic type HashMap<K,V> should be parameterized.

原文由 skiphoppy 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.9k
2 个回答

哇;我想我找到了自己问题的答案。我只是不确定它是否值得! :)

问题是没有检查演员表。所以,你必须自己检查。您不能只使用 instanceof 检查参数化类型,因为参数化类型信息在运行时不可用,在编译时已被删除。

但是,您可以使用 instanceof 对散列中的每个项目执行检查,这样做,您可以构造一个类型安全的新散列。而且您不会引起任何警告。

感谢 mmyers 和 Esko Luontola,我已经参数化了我最初在这里编写的代码,因此它可以被封装在某个实用程序类中并用于任何参数化的 HashMap。如果您想更好地理解它并且对泛型不是很熟悉,我鼓励您查看此答案的编辑历史记录。

 public static <K, V> HashMap<K, V> castHash(HashMap input,
                                            Class<K> keyClass,
                                            Class<V> valueClass) {
  HashMap<K, V> output = new HashMap<K, V>();
  if (input == null)
      return output;
  for (Object key: input.keySet().toArray()) {
    if ((key == null) || (keyClass.isAssignableFrom(key.getClass()))) {
        Object value = input.get(key);
        if ((value == null) || (valueClass.isAssignableFrom(value.getClass()))) {
            K k = keyClass.cast(key);
            V v = valueClass.cast(value);
            output.put(k, v);
        } else {
            throw new AssertionError(
                "Cannot cast to HashMap<"+ keyClass.getSimpleName()
                +", "+ valueClass.getSimpleName() +">"
                +", value "+ value +" is not a "+ valueClass.getSimpleName()
            );
        }
    } else {
        throw new AssertionError(
            "Cannot cast to HashMap<"+ keyClass.getSimpleName()
            +", "+ valueClass.getSimpleName() +">"
            +", key "+ key +" is not a " + keyClass.getSimpleName()
        );
    }
  }
  return output;
}

这是很多工作,可能回报很少……我不确定我是否会使用它。对于人们是否认为值得或不值得发表任何评论,我将不胜感激。另外,我很感激改进建议:除了抛出 AssertionErrors 之外,我还能做些什么更好的事情?有更好的东西我可以扔吗?我应该将其设为已检查的异常吗?

原文由 skiphoppy 发布,翻译遵循 CC BY-SA 3.0 许可协议

当然,显而易见的答案是不要进行未经检查的转换。

如果绝对有必要,那么至少尝试限制 @SuppressWarnings 注释的范围。根据其 Javadocs ,它可以继续使用局部变量;这样,它甚至不会影响整个方法。

例子:

 @SuppressWarnings("unchecked")
Map<String, String> myMap = (Map<String, String>) deserializeMap();

无法确定 Map 是否真的应该具有通用参数 <String, String> 。您必须事先知道参数应该是什么(或者您会在获得 ClassCastException 时发现)。这就是代码生成警告的原因,因为编译器不可能知道是否安全。

原文由 Michael Myers 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题