首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么这段代码在编译时不发出‘`ClassCastException`’警告?

为什么这段代码在编译时不发出‘`ClassCastException`’警告?
EN

Stack Overflow用户
提问于 2021-09-21 15:42:05
回答 3查看 84关注 0票数 0

我见过这个问题,但它似乎没有回答以下两种情况,也没有引用任何进一步的文档,我很想阅读这些文档。

我有以下代码片段:

代码语言:javascript
复制
    public static void main(String[] args) {
        // compile-time OK
        // run-time ClassCastException
        Child noWarnings = (Child) getParent();

        // vs...

        // compile-time failure
        Child compileTimeFailure = new Parent();
    }
    
    private static Parent getParent() {
        return new Parent();
    }

    private static class Parent { }

    private static class Child extends Parent { }

代码段第4行上的代码生成,没有警告,但结果是ClassCastException。为什么编译器不能对此进行类型化?

如果我们加上一层间接的话,这就更奇怪了:

代码语言:javascript
复制
    public static void main(String[] args) {
        // compile-time OK
        // run-time ClassCastException
        Boxed noWarnings = new Boxed((Child) getParent());

        // vs...
        
        // compile-time OK, but warning is emitted correctly
        // run-time ClassCastException
        Boxed classCastWarning = new Boxed((Child) new Parent());
    }

    private static Parent getParent() {
        return new Parent();
    }

    private static class Boxed {
        public Boxed(Child data) {

        }
    }

    private static class Parent { }

    private static class Child extends Parent { }

编译器不允许第一个示例,但允许第二个示例,这似乎是不直观的.

任何关于这两种情况的说明都将是最受欢迎的。

EN

回答 3

Stack Overflow用户

发布于 2021-09-21 15:43:41

为什么编译器不能对此进行类型化?

一些Parent实例是Child的实例,因为所有的Child都是Parent。编译器不知道将返回的实例是否为Child,但可能是。所以它允许它。

事实上,作为斯蒂芬C指出,JLS不允许编译器将其称为编译错误。

具体来说,语言规范说

如果操作数的编译时类型不能通过转换(§5.5)转换为强制转换操作符指定的目标类型,则会发生编译时错误。

(它还描述了转换表达式中出现编译时错误的另一种情况;但这些错误在这里不适用,因为没有一个或多个AdditionalBound术语)。

Parent可以由变窄参考转换转换为Child,这样编译时错误就不会发生.

Boxed classCastWarning = new Boxed((Child) new Parent());

这显然会失败。new Parent()不是Child的实例,而是Parent的实例。

但是编译器实际上并没有在强制转换的上下文中考虑任何关于new Parent()的内容,除了它是Parent类型的表达式之外,它必须允许您将其转换为Child

但这并不是说不允许像IDE这样的工具给您一个警告(甚至是一个错误,如果您有这样的配置):通过静态分析可以清楚地看到,new Parent()将完全是Parent的一个实例(因为这就是new Parent()所能做到的),所以将其转换到子类将失败。您的工具可以告诉您规范中没有具体说明的内容。

票数 1
EN

Stack Overflow用户

发布于 2021-09-21 16:21:40

除了现有的答案之外,我还想强调为什么在编译期间不容易计算这个异常。

下面的例子也来自于https://docs.oracle.com/javase/specs/jls/se11/html/jls-5.html#jls-5.5的摘录,还有我的一些补充。

代码语言:javascript
复制
class Point { int x, y; }

interface Colorable { void setColor(int color); }

class ColoredPoint extends Point implements Colorable {
    int color;
    public void setColor(int color) { this.color = color; }
}
final class EndPoint extends Point {}

class Test {
    public static void main(String[] args) {
        Point p = new Point();
        ColoredPoint cp = new ColoredPoint();
        Colorable c;
        // The following may cause errors at run time because
        // we cannot be sure they will succeed; this possibility
        // is suggested by the casts:

        cp = (ColoredPoint)p; // p might not reference an
                              // object which is a ColoredPoint
                              // or a subclass of ColoredPoint

        // this wont throw casts exception as references to object is valid
        Point refPoint = new ColoredPoint();
        cp = (ColoredPoint)refPoint; // perfectly valid

        c = (Colorable)p;      // p might not be Colorable

        // The following are incorrect at compile time because
        // they can never succeed as explained in the text:
        Long l = (Long)p;            // compile-time error #1
        EndPoint e = new EndPoint();
        c = (Colorable)e;            // compile-time error #2
    }
}

这个示例本身在大多数情况下都是不言自明的,但是您可以进一步阅读上面的文档。

票数 1
EN

Stack Overflow用户

发布于 2021-09-21 15:44:27

ClassCastExceptions从不在编译时发生。所有异常都发生在运行时。您可以在编写代码时检查IDE的设置以获得提示。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69271809

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档