什么是未经检查的演员表,如何查看?

时间:2010-04-22 17:52:05

标签: java eclipse casting unchecked

我认为我得到的是未经检查的强制转换(从一个到另一个不同类型的转换),但是“检查”演员是什么意思?如何检查演员表以便我可以在Eclipse中避免这个警告?

3 个答案:

答案 0 :(得分:43)

更多地阐述彼得写的内容:

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

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

第3行中未经检查的警告表示编译器不再能够保证类型安全,因为稍后可能会发生意外的ClassCastException。这发生在第4行,执行隐式演员。

答案 1 :(得分:33)

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

Set<String> set = new HashSet();

会产生这样的警告。

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

  

消除所有未经检查的警告。如果您   消除所有警告,你可以放心,你的代码是类型安全的,这是非常的   好事。这意味着您不会在运行时获得ClassCastException   增加您对程序按预期行为的信心。

     

如果你无法消除警告,你可以证明那个代码   挑起警告是类型安全,然后(并且只有那时)抑制警告   带有@SuppressWarnings("unchecked")注释。如果您禁止警告   没有首先证明代码是类型安全的,你只是给自己一个   虚假的安全感。代码可以编译而不会发出任何警告,但是   它仍然可以在运行时抛出ClassCastException。但是,如果你忽略了   未经检查的警告,你知道是安全的(而不是压制它们),你   当一个新的警告突然出现代表一个真正的问题时,我们不会注意到该   在你没有沉默的所有误报中,新警告会丢失。

当然,消除与上述代码一样的警告并不总是那么容易。如果没有看到您的代码,就无法告诉如何使其安全。

答案 2 :(得分:0)

与已检查的强制转换相比,未经检查的强制转换不会在运行时检查类型安全性。

以下是基于第3版的Consider typesafe heterogenous containers部分的示例。 &#34;有效的Java&#34;作者Joshua Bloch,但容器类被故意破坏 - 它存储并返回错误的类型:

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),则运行此计划会导致ClassCastExceptionInteger 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()使用已检查的广告 -  key.cast(map.get(key)) - 运行此程序将导致ClassCastException出现在key.cast(map.get(key))行,因为经过检查的强制转换会发现该类型错误并抛出异常。 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)

看起来差别不大,但对于未经检查的演员,String成功进入了List<Integer>。在现实世界的应用中,这可能是......严重的后果。如果选中了演员表,则会尽早发现类型不匹配。

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

正如约书亚布洛赫所说,

  

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

为了完整起见,this回答了Eclipse的具体细节。