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

How do I address unchecked cast warnings?

提问人:skiphoppy 提问时间:2/4/2009 最后编辑:Chris Stillwellskiphoppy 更新时间:9/2/2022 访问量:532934

问:

Eclipse 给了我以下形式的警告:

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

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

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

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

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

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.
Java 泛型 警告

评论

0赞 Tom Hawtin - tackline 2/4/2009
如果你像这样使用 HttpSession,请查看 Brian Goetz 关于这个主题的文章:ibm.com/developerworks/library/j-jtp09238.html
0赞 Philip Guin 7/17/2012
如果未经检查的强制转换是不可避免的,一个好主意是将其与逻辑上表示其类型的东西(例如 的 甚至实例 )紧密耦合,这样您就可以看一眼它并知道它是安全的。enumClass<T>
4赞 blahdiblah 3/12/2013
相关/欺骗:类型安全:未检查的投射
3赞 Raedwald 5/17/2013
类型安全:未选中的强制转换的可能重复项
1赞 JGFMK 1/16/2020
我要补充一点,我发现我只能在包含违规代码的方法级别添加@SuppressWarnings(“未选中”)。因此,我将代码分解为一个例程,我必须这样做。我一直认为你可以在相关行的上方立即执行此操作。

答:

1赞 Mark Davidson 2/4/2009 #1

如果你发布你的代码,一个快速的猜测可以肯定地说,但你可能已经做了一些类似的事情

HashMap<String, Object> test = new HashMap();

这将在您需要时产生警告

HashMap<String, Object> test = new HashMap<String, Object>();

可能值得一看

Java 编程语言中的泛型

如果您不熟悉需要做什么。

评论

1赞 skiphoppy 2/4/2009
不幸的是,情况并非易事。代码已添加。
1赞 staticsan 9/17/2010
我来这里是为了寻找一个稍微不同的问题的答案:你准确地告诉我我需要什么!谢谢!
2赞 phihag 2/4/2009 #2

我可能误解了这个问题(一个例子和几行周围的行会很好),但你为什么不总是使用合适的接口(和 Java5+)?我看不出你为什么会想投给 a 而不是 .事实上,我无法想象有任何理由将变量的类型设置为而不是。HashMapMap<KeyType,ValueType>HashMapMap

为什么来源是?它是旧集合的参数类型吗?如果是这样,请使用泛型并指定所需的类型。Object

评论

2赞 skiphoppy 2/4/2009
我很确定在这种情况下切换到 Map 不会改变任何事情,但感谢您的编程技巧,这可能会改变我做一些事情的方式,变得更好。对象的源是我无法控制的 API(添加的代码)。
610赞 Michael Myers 2/4/2009 #3

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

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

例:

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

没有办法确定是否真的应该有泛型参数。您必须事先知道参数应该是什么(否则当您得到 ).这就是代码生成警告的原因,因为编译器不可能知道是否安全。Map<String, String>ClassCastException

评论

126赞 thSoft 5/26/2010
+1 指出它可以在局部变量上进行。Eclipse 只提供将其添加到整个方法中......
17赞 sweetfa 2/1/2012
Eclipse 3.7 (Indigo) 支持将未选中的变量添加到局部变量。
80赞 Theodore Norvell 3/1/2013
警告不仅仅是因为编译器不知道强制转换是安全的。例如,即使编译器不知道强制转换是安全的,也不会收到任何警告。之所以出现警告,是因为编译器 (a) 不知道强制转换是安全的,并且 (b) 不会在强制转换时生成完整的运行时检查。将检查它是否是 ,但不会检查它是否是 .String s = (String) new Object() ;HashmapHashMap<String,String>
10赞 Ti Strga 8/1/2013
可悲的是,即使强制转换和警告是针对赋值的,注释也必须在变量声明上进行......因此,如果声明和赋值位于不同的位置(例如,分别在“try”块的外部和内部),Eclipse 现在会生成两个警告:原始的未检查强制转换和新的“不必要的注释”诊断。
6赞 Jeff Lockhart 6/11/2015
对于需要伴随局部变量声明的注释(可能与实际强制转换位于不同行的不同作用域中),解决方法是在强制转换范围内创建一个局部变量,专门用于在与声明相同的行上执行强制转换。然后将此变量分配给不同作用域中的实际变量。这也是我用来抑制强制转换为实例变量的警告的方法,因为注释也不能在这里应用。
0赞 Rick 2/4/2009 #4

只需在投射之前对其进行类型检查即可。

Object someObject = session.getAttribute("attributeKey");
if(someObject instanceof HashMap)
HashMap<String, String> theHash = (HashMap<String, String>)someObject;  

对于任何询问的人来说,收到您不确定类型的对象是很常见的。许多遗留的“SOA”实现传递了各种对象,而这些对象不应该总是信任。(恐怖!

编辑更改了一次示例代码以匹配海报的更新,并且在一些评论之后,我看到 instanceof 不能很好地与泛型配合。但是,更改检查以验证外部对象似乎与命令行编译器配合得很好。修改后的示例现已发布。

评论

8赞 skiphoppy 2/4/2009
不幸的是,泛型使这是不可能的。它不仅仅是一个 HashMap,它还是一个包含类型信息的 HashMap。如果我删除了这些信息,我只会将警告推送到其他地方。
114赞 skiphoppy 2/4/2009 #5

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

问题是没有检查演员表。所以,你必须自己检查。不能只使用 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 之外,我还能做些什么更好的事情吗?有没有更好的东西可以扔?我应该将其设置为选中的例外吗?

评论

71赞 Dustin Getz 3/2/2011
这些东西令人困惑,但我认为您所做的只是将 ClassCastExceptions 换成 AssertionErrors。
62赞 Craig B 12/19/2011
伙计,这绝对不值得!想象一下,可怜的 sap 必须回来修改一些代码,里面有一团糟。我不喜欢压制警告,但我认为这是这里较小的邪恶。
74赞 Dan Is Fiddling By Firelight 9/11/2012
这不仅仅是因为它是一个丑陋的、令人困惑的、混乱的(当你无法避免一个大量的评论可以引导维护程序员完成它时);遍历集合中的每个元素将强制转换从 O(1) 操作转换为 O(n) 操作。这是万万没想到的,很容易变成可怕的神秘减速。
23赞 skiphoppy 12/8/2012
@DanNeely你是对的。一般来说,没有人应该这样做。
4赞 MetroidFan2002 3/7/2014
一些评论...方法签名是错误的,因为它没有“投射”一个该死的东西,它只是将现有地图复制到新地图中。此外,它可能被重构为接受任何映射,而不依赖于 HashMap 本身(即在方法签名中获取 Map 并返回 Map,即使内部类型是 HashMap)。你真的不需要对新地图进行转换或存储 - 如果你没有抛出断言错误,那么给定的地图现在里面有正确的类型。使用泛型类型创建新地图是没有意义的,因为您仍然可以将其设置为原始地图并放置任何内容。
186赞 Julien Chastang 2/4/2009 #6

不幸的是,这里没有很好的选择。请记住,所有这些工作的目标都是为了保持类型安全。“Java 泛型”为处理非泛型遗留库提供了一种解决方案,在第 8.2 节中有一个特别称为“空循环技术”的解决方案。基本上,进行不安全的强制转换,并禁止显示警告。然后像这样遍历地图:

@SuppressWarnings("unchecked")
Map<String, Number> map = getMap();
for (String s : map.keySet());
for (Number n : map.values());

如果遇到意外类型,您将获得一个 运行时 ,但至少它会在问题根源附近发生。ClassCastException

评论

7赞 Stijn de Witt 6/7/2014
比skiphoppy提供的答案要好得多,原因有很多:1)这段代码要短得多。2) 此代码实际上按预期抛出 ClassCastException。3) 此代码不执行源映射的完整副本。4) 循环可以很容易地包装在断言中使用的单独方法中,这很容易消除生产代码中的性能影响。
6赞 RenniePet 9/23/2014
Java 编译器或 JIT 编译器是否有可能决定不使用此代码的结果,并通过不编译它来“优化”它?
1赞 GrandOpener 5/29/2016
如果它可能引发异常,它就不是真正的死代码。我对目前使用的 JIT 编译器了解得不够多,无法保证它们都不会搞砸,但我相当有信心地说它们不应该这样做。
3赞 user2219808 8/28/2018
这仍然不能保证类型安全,因为仍在使用相同的映射。它最初可能被定义为 Map<Object,Object>恰好有字符串和数字,然后如果添加了布尔值,那么此代码的用户将得到一个令人困惑且难以追踪的惊喜。保证类型安全的唯一方法是将其复制到具有请求类型的新映射中,以保证允许进入其中的内容。
2赞 Fortyrunner 2/4/2009 #7

如果我必须使用不支持泛型的 API..我尝试用尽可能少的行将这些调用隔离在包装器例程中。然后,我使用 SuppressWarnings 注释,并同时添加类型安全强制转换。

这只是个人喜好,以保持事物尽可能整洁。

29赞 Esko Luontola 2/4/2009 #8

您可以创建如下所示的实用程序类,并使用它来禁止显示未选中的警告。

public class Objects {

    /**
     * Helps to avoid using {@code @SuppressWarnings({"unchecked"})} when casting to a generic type.
     */
    @SuppressWarnings({"unchecked"})
    public static <T> T uncheckedCast(Object obj) {
        return (T) obj;
    }
}

您可以按如下方式使用它:

import static Objects.uncheckedCast;
...

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

关于这一点的更多讨论在这里:http://cleveralias.blogs.com/thought_spearmints/2006/01/suppresswarning.html

评论

22赞 Dustin Getz 3/2/2011
不是反对票,但包装器除了抑制警告之外,什么都没有增加。
4赞 Tino 8/1/2014
+1,因为这种解决方案不会浪费宝贵的代码行。
1赞 Tino 8/30/2018
@ErikE太多了。更昂贵、更大、更高分辨率的显示器,为所有这些浪费的线路腾出空间,一张更大的桌子来放置所有这些更大的显示器,一个更大的空间来放置更大的桌子,以及一个有见地的老板......
1赞 Tino 8/30/2018
@ErikE 滚动条,用于 ?开什么玩笑?vi
8赞 Esko Luontola 2/4/2009 #9

在这种特殊情况下,我不会将 Maps 直接存储到 HttpSession 中,而是将我自己类的实例存储到其中,而该类又包含 Map(类的实现细节)。然后,您可以确定地图中的元素类型正确。

但是,如果您仍然想检查地图的内容是否正确,则可以使用如下代码:

public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("a", 1);
    map.put("b", 2);
    Object obj = map;

    Map<String, Integer> ok = safeCastMap(obj, String.class, Integer.class);
    Map<String, String> error = safeCastMap(obj, String.class, String.class);
}

@SuppressWarnings({"unchecked"})
public static <K, V> Map<K, V> safeCastMap(Object map, Class<K> keyType, Class<V> valueType) {
    checkMap(map);
    checkMapContents(keyType, valueType, (Map<?, ?>) map);
    return (Map<K, V>) map;
}

private static void checkMap(Object map) {
    checkType(Map.class, map);
}

private static <K, V> void checkMapContents(Class<K> keyType, Class<V> valueType, Map<?, ?> map) {
    for (Map.Entry<?, ?> entry : map.entrySet()) {
        checkType(keyType, entry.getKey());
        checkType(valueType, entry.getValue());
    }
}

private static <K> void checkType(Class<K> expectedType, Object obj) {
    if (!expectedType.isInstance(obj)) {
        throw new IllegalArgumentException("Expected " + expectedType + " but was " + obj.getClass() + ": " + obj);
    }
}

评论

1赞 skiphoppy 2/4/2009
棒;我想我可以将其与我的答案结合起来,将其参数化并避免完全禁止警告!
1赞 Tino 8/1/2014
+1 可能是最好的配方(易于理解和维护),可以通过运行时检查安全地做到这一点
1赞 Tom Hawtin - tackline 2/4/2009 #10

计算机科学中几乎每个问题都可以通过添加间接*或其他东西来解决。

因此,引入一个非泛型对象,该对象的级别高于 .在没有上下文的情况下,它看起来不会很有说服力,但无论如何:Map

public final class Items implements java.io.Serializable {
    private static final long serialVersionUID = 1L;
    private Map<String,String> map;
    public Items(Map<String,String> map) {
        this.map = New.immutableMap(map);
    }
    public Map<String,String> getMap() {
        return map;
    }
    @Override public String toString() {
        return map.toString();
    }
}

public final class New {
    public static <K,V> Map<K,V> immutableMap(
        Map<? extends K, ? extends V> original
    ) {
        // ... optimise as you wish...
        return Collections.unmodifiableMap(
            new HashMap<String,String>(original)
        );
    }
}

static Map<String, String> getItems(HttpSession session) {
    Items items = (Items)
        session.getAttribute("attributeKey");
    return items.getMap();
}

*除了太多的间接级别。

评论

1赞 Stephen C 11/19/2013
这句话出自已故的大卫·惠勒教授之手。en.wikipedia.org/wiki/......
13赞 Joachim Sauer 2/5/2009 #11

在HTTP会话世界中,您无法真正避免强制转换,因为API是这样编写的(仅接受和返回)。Object

不过,只要稍加努力,你就可以轻松避免不受检查的演员阵容。这意味着它将变成一个传统的演员阵容,在发生错误时给予权利)。未经检查的异常可能会在以后的任何时候变成 a,而不是强制转换的点(这就是为什么它是一个单独的警告的原因)。ClassCastExceptionCCE

将 HashMap 替换为专用类:

import java.util.AbstractMap;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Attributes extends AbstractMap<String, String> {
    final Map<String, String> content = new HashMap<String, String>();

    @Override
    public Set<Map.Entry<String, String>> entrySet() {
        return content.entrySet();
    }

    @Override
    public Set<String> keySet() {
        return content.keySet();
    }

    @Override
    public Collection<String> values() {
        return content.values();
    }

    @Override
    public String put(final String key, final String value) {
        return content.put(key, value);
    }
}

然后强制转换为该类而不是,所有内容都将在编写代码的确切位置进行检查。后来没有意外。Map<String,String>ClassCastExceptions

评论

0赞 GPrathap 11/18/2015
这确实是一个非常有用的答案。
0赞 Luke 10X 6/12/2010 #12

如果您确定 session.getAttribute() 返回的类型是 HashMap,那么您不能将类型转换为该确切类型,而只能依靠检查通用 HashMap

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

然后,Eclipse 会发出令人惊讶的警告,但当然这可能会导致难以调试的运行时错误。我只在操作关键型上下文中使用这种方法。

2赞 jfreundo 10/14/2010 #13

以这个为例,它比创建一个新的 HashMap 要快得多,如果它已经是一个,但仍然是安全的,因为每个元素都根据它的类型进行检查......

@SuppressWarnings("unchecked")
public static <K, V> HashMap<K, V> toHashMap(Object input, Class<K> key, Class<V> value) {
       assert input instanceof Map : input;

       for (Map.Entry<?, ?> e : ((HashMap<?, ?>) input).entrySet()) {
           assert key.isAssignableFrom(e.getKey().getClass()) : "Map contains invalid keys";
           assert value.isAssignableFrom(e.getValue().getClass()) : "Map contains invalid values";
       }

       if (input instanceof HashMap)
           return (HashMap<K, V>) input;
       return new HashMap<K, V>((Map<K, V>) input);
    }

评论

0赞 user102008 8/16/2011
key.isAssignableFrom(e.getKey().getClass())可以写成key.isInstance(e.getKey())
23赞 Dustin Getz 3/2/2011 #14

这些东西很难,但这是我目前的想法:

如果你的 API 返回 Object,那么你就无能为力了——无论如何,你都会盲目地转换对象。你让 Java 抛出 ClassCastExceptions,或者你可以自己检查每个元素并抛出 Assertions 或 IllegalArgumentExceptions 之类的,但这些运行时检查都是等效的。无论您在运行时执行什么操作,都必须禁止编译时未检查的强制转换。

我宁愿盲投并让 JVM 为我执行运行时检查,因为我们“知道”API 应该返回什么,并且通常愿意假设 API 有效。如果需要,请在演员表上方的任何地方使用泛型。你并没有真正在那里购买任何东西,因为你仍然有单一的盲转换,但至少你可以从那里开始使用泛型,这样 JVM 可以帮助你避免其他代码片段中的盲转换。

在这种特殊情况下,大概您可以看到对 SetAttribute 的调用并看到类型正在进入,因此在退出时将类型盲投为 same 并不是不道德的。添加引用 SetAttribute 的注释并完成它。

0赞 mike rodent 3/22/2011 #15

有两种方法,一种是完全避免标签,另一种使用顽皮但不错的实用方法。
问题是预通用的集合......
我相信经验法则是:“一次投射一个对象”——当试图在泛型世界中使用原始类时,这意味着因为你不知道这个 Map 中有什么<?, ?>(事实上,JVM 甚至可能会发现它甚至不是一个 Map!),当你想到它时,很明显你不能投射它。如果你有一个 Map<String, ?> map2,那么 HashSet<String> keys = (HashSet<String>)map2.keySet() 不会给你警告,尽管这对编译器来说是一种“信仰行为”(因为它可能会变成一个 TreeSet)......但这只是一个单一的信仰行为。

PS 对于像我的第一种方式一样迭代“很无聊”并且“需要时间”的反对意见,答案是“没有痛苦就没有收获”:通用集合保证包含 Map.Entry<String、String>s,而不是其他任何东西。您必须为此保证付费。当系统地使用泛型时,这种支付,很漂亮,采取编码合规性的形式,而不是机器时间!
有一种观点可能会说,你应该将 Eclipse 的设置设置为使这种未经检查的强制转换错误,而不是警告。在这种情况下,您将不得不使用我的第一种方式。

package scratchpad;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

public class YellowMouse {

    // First way

    Map<String, String> getHashMapStudiouslyAvoidingSuppressTag(HttpSession session) {
      Map<?, ?> theHash = (Map<?, ?>)session.getAttribute("attributeKey");

      Map<String, String> yellowMouse = new HashMap<String, String>();
      for( Map.Entry<?, ?> entry : theHash.entrySet() ){
        yellowMouse.put( (String)entry.getKey(), (String)entry.getValue() );
      }

      return yellowMouse;
    }


    // Second way

    Map<String, String> getHashMapUsingNaughtyButNiceUtilityMethod(HttpSession session) {
      return uncheckedCast( session.getAttribute("attributeKey") );
    }


    // NB this is a utility method which should be kept in your utility library. If you do that it will
    // be the *only* time in your entire life that you will have to use this particular tag!!

    @SuppressWarnings({ "unchecked" })
    public static synchronized <T> T uncheckedCast(Object obj) {
        return (T) obj;
    }


}

评论

0赞 Matteo Italia 3/25/2011
您没有评论权限的事实不允许您编辑他人的答案以添加您的评论;你编辑别人的答案是为了改进他们的格式、语法等,而不是添加你对他们的意见。当你达到 50 代表时,你将能够在任何地方发表评论,与此同时,我很确定你可以抗拒(或者,如果你真的不能,把你的评论写到你帖子中的现有答案)。(其他人注意:我写这篇文章是因为我看到 - 并拒绝了 - 他对审核工具中其他帖子的评论编辑)
8赞 Gonen I 8/11/2011 #16

Esko Luontola 在上面的答案中的 Objects.Unchecked 实用程序函数是避免程序混乱的好方法。

如果你不希望整个方法上的 SuppressWarnings,Java 会强制你把它放在本地方法上。如果需要对成员进行强制转换,则可能导致如下代码:

@SuppressWarnings("unchecked")
Vector<String> watchedSymbolsClone = (Vector<String>) watchedSymbols.clone();
this.watchedSymbols = watchedSymbolsClone;

使用该实用程序要干净得多,并且您在做什么仍然很明显:

this.watchedSymbols = Objects.uncheckedCast(watchedSymbols.clone());

注意:我觉得重要的是要补充一点,有时警告真的意味着你做错了什么,比如:

ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(1);
Object intListObject = intList; 

 // this line gives an unchecked warning - but no runtime error
ArrayList<String> stringList  = (ArrayList<String>) intListObject;
System.out.println(stringList.get(0)); // cast exception will be given here

编译器告诉您的是,在运行时不会检查此强制转换,因此在您尝试访问泛型容器中的数据之前,不会引发运行时错误。

52赞 Dave 10/22/2011 #17

在 Eclipse 首选项中,转到 Java->Compiler->Errors/Warnings->Generic types 并选中该复选框。Ignore unavoidable generic type problems

这满足了问题的意图,即

我想避免 Eclipse 警告......

如果不是精神。

评论

1赞 dimo414 2/9/2015
啊,谢谢你:)我在 中遇到了一个“”错误,但添加使 Eclipse 不高兴,声称抑制是不必要的。取消选中此框会使 Eclipse 和行为相同,这就是我想要的。在代码中显式禁止显示警告比在 Eclipse 中禁止所有位置的警告要清晰得多。uses unchecked or unsafe operations.javac@SuppressWarnings("unchecked")javac
-6赞 Marc Riehm 3/1/2013 #18

解决方案:在 Eclipse 中禁用此警告。不要@SuppressWarnings它,只需完全禁用它。

上面介绍的几个“解决方案”是不合时宜的,为了抑制愚蠢的警告,使代码不可读。

评论

11赞 MByD 3/1/2013
请问为什么?全局禁用警告将隐藏存在此问题的其他地方。添加 A 不会使代码完全不可读。@SuppressWarnings
1赞 Jim Daehn 1/30/2015 #19

这是我在重写操作时处理此问题的一种方法。equals()

public abstract class Section<T extends Section> extends Element<Section<T>> {
    Object attr1;

    /**
    * Compare one section object to another.
    *
    * @param obj the object being compared with this section object
    * @return true if this section and the other section are of the same
    * sub-class of section and their component fields are the same, false
    * otherwise
    */       
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            // this exists, but obj doesn't, so they can't be equal!
            return false;
        }

        // prepare to cast...
        Section<?> other;

        if (getClass() != obj.getClass()) {
            // looks like we're comparing apples to oranges
            return false;
        } else {
            // it must be safe to make that cast!
            other = (Section<?>) obj;
        }

        // and then I compare attributes between this and other
        return this.attr1.equals(other.attr1);
    }
}

这似乎在 Java 8 中有效(即使编译为-Xlint:unchecked)

6赞 abbas 3/10/2015 #20

警告抑制不是解决方案。你不应该在一个语句中做两级强制转换。

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {

    // first, cast the returned Object to generic HashMap<?,?>
    HashMap<?, ?> theHash = (HashMap<?, ?>)session.getAttribute("attributeKey");

    // next, cast every entry of the HashMap to the required type <String, String>
    HashMap<String, String> returingHash = new HashMap<>();
    for (Entry<?, ?> entry : theHash.entrySet()) {
        returingHash.put((String) entry.getKey(), (String) entry.getValue());
    }
    return returingHash;
}

评论

1赞 Rup 3/13/2015
他五岁的问题?你需要做那么多工作吗?鉴于 Java 具有类型擦除功能,则第二个哈希图在运行时应与第一个哈希图相同;我认为如果您只是遍历条目并验证它们都是字符串的实例,它会更有效并避免复制。或者,TBH,检查您正在使用的 servlet JAR 的源代码,并验证它是否只放置字符串。
1赞 abbas 3/14/2015
直到今天,我在项目中都看到了这个警告。他的问题不在于验证类型,而在于将“放入”未施法的地图中而引起的警告。
18赞 StaticNoiseLog 8/13/2015 #21

下面是一个简短的示例,它通过采用其他答案中提到的两种策略来避免“未检查的强制转换”警告

  1. 在运行时将感兴趣类型的类作为参数传递 ()。然后,您可以使用:Class<T> inputElementClazzinputElementClazz.cast(anyObject);

  2. 对于 Collection 的类型转换,请使用通配符 ?而不是泛型类型 T,以确认您确实不知道从遗留代码中可以期望获得什么样的对象 ()。毕竟,这就是“未检查的投射”警告想要告诉我们的:我们不能确定我们得到了一个 ,所以诚实的做法是使用 .如果绝对需要,仍然可以构建已知类型的集合 ()。Collection<?> unknownTypeCollectionCollection<T>Collection<?>Collection<T> knownTypeCollection

以下示例中接口的旧代码在 StructuredViewer 中具有属性“input”(StructuredViewer 是树或表小部件,“input”是其背后的数据模型)。这个“输入”可以是任何类型的 Java 集合。

public void dragFinished(StructuredViewer structuredViewer, Class<T> inputElementClazz) {
    IStructuredSelection selection = (IStructuredSelection) structuredViewer.getSelection();
    // legacy code returns an Object from getFirstElement,
    // the developer knows/hopes it is of type inputElementClazz, but the compiler cannot know
    T firstElement = inputElementClazz.cast(selection.getFirstElement());

    // legacy code returns an object from getInput, so we deal with it as a Collection<?>
    Collection<?> unknownTypeCollection = (Collection<?>) structuredViewer.getInput();

    // for some operations we do not even need a collection with known types
    unknownTypeCollection.remove(firstElement);

    // nothing prevents us from building a Collection of a known type, should we really need one
    Collection<T> knownTypeCollection = new ArrayList<T>();
    for (Object object : unknownTypeCollection) {
        T aT = inputElementClazz.cast(object);
        knownTypeCollection.add(aT);
        System.out.println(aT.getClass());
    }

    structuredViewer.refresh();
}

当然,如果我们使用具有错误数据类型的旧代码(例如,如果我们将数组设置为 StructuredViewer 的“输入”而不是 Java 集合),则上述代码可能会产生运行时错误。

调用该方法的示例:

dragFinishedStrategy.dragFinished(viewer, Product.class);
10赞 Jan Moravec 9/2/2017 #22

在 Android Studio 中,如果您想停用检查功能,可以使用:

//noinspection unchecked
Map<String, String> myMap = (Map<String, String>) deserializeMap();