36

我想我明白了未经检查的演员表的含义(从一个不同类型的演员转换到另一个),但是“检查”演员表是什么意思?如何检查演员表,以便避免在 Eclipse 中出现此警告?

4

3 回答 3

49

详细说明彼得写的内容:

从非泛型类型到泛型类型的转换可能在运行时工作得很好,因为泛型参数在编译期间被删除,所以我们留下了合法的转换。ClassCastException但是,由于对类型参数的错误假设,代码稍后可能会因意外而失败。例如:

    List l1 = new ArrayList();
    l1.add(33);
    List<String> l2 = (List<String>) l1;
    String s = l2.get(0);

第 3 行未经检查的警告表明编译器无法保证类型安全,因为以后可能会发生意外的 ClassCastException。实际上,这发生在执行隐式转换的第 4 行。

于 2010-04-22T18:12:09.593 回答
34

未经检查的强制转换意味着您(隐式或显式)从泛型类型转换为非限定类型或相反。例如这条线

Set<String> set = new HashSet();

会产生这样的警告。

通常出现此类警告是有充分理由的,因此您应该尝试改进代码而不是抑制警告。引自 Effective Java,第 2 版:

尽可能消除所有未经检查的警告。如果您消除了所有警告,则可以确保您的代码是类型安全的,这是一件非常好的事情。这意味着您不会ClassCastException在运行时得到 a,它增加了您对程序按预期运行的信心。

如果您不能消除警告,并且您可以证明引发警告的代码是类型安全的,那么(并且只有这样)使用@SuppressWarnings("unchecked")注释来抑制警告。如果您在没有首先证明代码是类型安全的情况下抑制警告,那么您只会给自己一种错误的安全感。代码可以在不发出任何警告的情况下编译,但它仍然可以ClassCastException在运行时抛出 a。但是,如果您忽略了您知道是安全的未经检查的警告(而不是抑制它们),您将不会注意到何时出现代表真正问题的新警告。新的警告将在您没有消除的所有误报中消失。

当然,消除警告并不总是像上面的代码那样容易。如果没有看到您的代码,则无法说明如何使其安全。

于 2010-04-22T17:53:21.963 回答
2

与检查强制转换相反,未检查强制转换不会在运行时检查类型安全。

这是一个基于Consider typesafe heterogenous containers第 3 版部分的示例。Joshua Bloch 的“Effective Java”,但容器类被故意破坏 - 它存储并返回错误的类型:

public class Test {

    private static class BrokenGenericContainer{
        private final Map<Class<?>, Object> map= new HashMap<>();

        public <T> void store(Class<T> key, T value){
            map.put(key, "broken!"); // should've been [value] here instead of "broken!"
        }

        public <T> T retrieve(Class<T> key){
//          return key.cast(map.get(key)); // a checked cast 
            return (T)map.get(key);        // an unchecked cast
        }

    }

    public static void main(String[] args) {
        BrokenGenericContainer c= new BrokenGenericContainer();
        c.store(Integer.class, 42);
        List<Integer> ints = new ArrayList<>();
        ints.add(c.retrieve(Integer.class));
        Integer i = ints.get(0);
    }

}


如果retrieve()使用未经检查的演员表- (T)map.get(key)- 运行此程序将导致ClassCastException发生Integer i = ints.get(0)在线。该retrieve()方法将完成,因为在运行时未检查实际类型:

Exception in thread "main" 
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Test.main(Test.java:27)


但是如果retrieve()使用checked cast——运行 key.cast(map.get(key))这个程序会导致ClassCastException发生在key.cast(map.get(key))line,因为checked cast会发现类型错误并抛出异常。该retrieve()方法将无法完成:

Exception in thread "main" java.lang.ClassCastException: 
                                          Cannot cast java.lang.String to java.lang.Integer
    at java.lang.Class.cast(Class.java:3369)
    at Test$BrokenGenericContainer.retrieve(Test.java:16)
    at Test.main(Test.java:26)

看起来差别不大,但在未经检查的演员表的情况下, aString成功进入了List<Integer>. 在现实世界的应用中,这种情况的后果可能是……嗯,很严重。在检查强制转换的情况下,尽早发现类型不匹配。


@SuppressWarnings("unchecked")如果程序员确实确定该方法实际上是安全的,则可以使用以避免未经检查的强制转换警告。更好的选择是尽可能使用泛型和检查强制转换。

正如约书亚·布洛赫所说,

...未经检查的警告很重要。不要忽视他们。


为了完整起见,答案涉及 Eclipse 细节。

于 2018-02-12T20:56:15.637 回答