【问题标题】:Unchecked cast - should I suppress this?未经检查的演员表 - 我应该压制这个吗?
【发布时间】:2026-02-07 12:30:02
【问题描述】:

这里是初学者 Java 编码器。代码如下:

private ArrayList<Rectangle> rectangles;
try {
        InputStream IS = MyClass.class.getResourceAsStream("file.dat");
        ObjectInputStream input = new ObjectInputStream(IS);
        rectangles = (ArrayList<Rectangle>) input.readObject();
} catch (IOException | ClassNotFoundException ex) {
        System.out.println(ex);
}

Netbeans 告诉我这是未经检查的演员表。谷歌告诉我我应该尽量避免这个警告而不是压制它,那么我该怎么做呢?该程序应该读取的唯一文件确实包含一个 ArrayList,如果没有,我可以捕获这些异常。

此外,如果我对 char[][] 执行相同操作(从 OIS 中读取并尝试转换),netbeans 不会有任何问题。这是为什么?我认为这仍然是未经检查的演员表。

【问题讨论】:

    标签: java casting unchecked


    【解决方案1】:

    只有在知道警告的原因时才应该取消警告。在这种情况下,因为听起来您理解问题并正在采取措施处理它,所以压制它可能是可以的。但是,如果您一心想让警告消失,那么在这种情况下,我发现的唯一方法是执行以下操作:

    public class ListOfRectangles extends ArrayList<Rectangle> {}
    

    然后使用ListOfRectangles 作为您的数据类型,用于在文件之间进行序列化。

    编译器可以使用char [] [] 而不是ArrayList&lt;Rectangle&gt; 的原因是因为Java 泛型的概念称为擦除。这意味着对于泛型类型(如ArrayList),参数化类型(在本例中为Rectangle)实际上并不存在于字节码中。它仅在编译时存在,以便编译器可以仔细检查您的工作。数组不是这种情况。

    对泛型有更深入的了解here

    【讨论】:

      【解决方案2】:

      有时要避免演员阵容简直是不可能或太难了。无论如何都要通过始终分配检查类型来避免它们。但如果你不能,那么就压制它。恕我直言。

      在这种情况下,压制它看起来完全合法。这比返回Object 更好。

      【讨论】:

        【解决方案3】:

        总是尽量避免这个警告而不是抑制它,这样可以降低运行时错误的机会。

        【讨论】:

        • 运行时错误是检查或未检查演员表的利害关系。唯一的区别是该错误的确切位置。
        【解决方案4】:

        尽可能避免,否则记录。以下是 Josh Bloch 推荐的记录方式(Effective Java,第 2 版,第 26 条):

        private ArrayList<Rectangle> rectangles;
         try {
                 InputStream IS = MyClass.class.getResourceAsStream("file.dat");
                 ObjectInputStream input = new ObjectInputStream(IS);
        
                 //The input stream is definitely an ArrayList<Rectangle>
                 //I know this because...............
                 @SuppressWarnings("unchecked")
                 ArrayList<Rectangle> rectangles2 = (ArrayList<Rectangle>) input.readObject();
                 rectangles = rectangles2;
        
         } catch (IOException | ClassNotFoundException ex) {
                 System.out.println(ex);
        }
        

        这会将抑制本地化为几行代码,而不是整个函数。

        【讨论】:

        • 说你有一个错误要修复。你会相信评论然后走开吗?如果您的回答是“是”,那么您无法胜任调试任务。换句话说,忘记评论。
        • 最好是一个非常好的和有用的评论,否则它是值得信赖的。如果它对调试没有帮助,它不应该在那里。
        • 注释和代码有各自独立的生命。我是否应该深入挖掘 git 历史以首先跟踪添加评论的原始提交,然后进行任何修改以决定每个修改是否保持评论中解释的属性?没办法,我花时间亲自检查代码在做什么。事实上,学习如何完全忽略注释以防止在阅读代码时误入歧途,这需要练习。这对我来说是一个伤害
        • 这就像接受魔术师的请求“现在,请不要注意我的右手。”
        • 聪明的程序员知道哪些 cmets 可以忽略,哪些应该注意。他们还知道如何编写和维护不太可能被忽略的 cmets。
        【解决方案5】:

        抑制警告可能是合法的。例如,如果您绝对确定序列化格式,则可以取消它。

        但是,如果您不确定,因为其他人制作了序列化格式,或者您认为格式可能会随着时间的推移而演变,您可以在不执行任何不安全转换的情况下验证内容。

        List<?> untyped = (List<?>) input.readObject();
        List<Rectangle> rectangles = new ArrayList<>(untyped.size());
        for (Object obj : untyped)
          rectangles.add((Rectangle) obj);
        

        这将确保如果一个元素不是Rectangle,则生成的ClassCastException 将立即在显式转换的位置被抛出,而不是稍后在没有执行明显转换的位置。

        【讨论】:

          最近更新 更多