为什么ClassCastException是运行时错误?

时间:2014-08-29 02:02:51

标签: java types

尝试以下方法:

class Base {
    public Base(){
    }
}

class Derived extends Base {
}

public class Main
{
    public static void main (String[] args)
    {
        Derived derived = (Derived) new Base();
    }
}

导致CastClassException,但成功编译。对this question的评论表明,编译器无法确定new Base()在运行时之前的类型 - 但为什么会出现这种情况呢?我知道在other type systems中,编译器总是可以推断出任何表达式的类型,并且Java编译器当然可以使用例如lambda表达式。在某些时候,如果它发出正确的字节码,它必须知道new Base()的类型。

是否有理论上的限制阻止Java编译器在程序运行之前捕获它,或者它是一个实现选择?

3 个答案:

答案 0 :(得分:5)

public static void main(String[] args) throws Exception {
    Derived derived = (Derived) getObject();
}

public static Base getObject() {
    if (Math.random() > 0.5) {
        return new Base();
    } else {
        return new Derived();
    }
}

现在怎么办?编译器如何知道?编译器(大部分)仅限于静态信息。对象的类型是动态信息。

答案 1 :(得分:3)

允许子类化的语言的任何合理实现都有可能出现强制转换异常(或其等价物)。

子类化方案的强大之处在于,您可以拥有在通用超类上运行的方法,而无需知道特定的子类。但是迟早会需要对子类进行特定的操作,并且必须将引用强制转换为子类。如果该转换是错误的,因为你误认为对象的实际类,那么逻辑上应该发生转换异常。

您可以隐藏某些机制背后的强制转换异常,例如,如果对象不是正确的类型,则返回NULL,但这只是将一个异常替换为另一个异常。

答案 2 :(得分:1)

new Base()的结果是Base,在任何其他上下文中可能Derived.编译器不会传播其中的特殊知识这种情况确实是Base.

  

是否有理论上的限制阻止Java编译器在程序运行之前捕获它,或者它是一个实现选择?

这是一个实现选择,不是为了说明它的特殊情况。