【问题标题】:Java casting resulting in run-time error instead of compilation errorJava 转换导致运行时错误而不是编译错误
【发布时间】:2012-04-30 17:47:04
【问题描述】:

以下代码 sn -p 将导致运行时:

class Vehicle {
    public void printSound() {
        System.out.print("vehicle");
    }
}

class Car extends Vehicle {
    public void printSound() {
        System.out.print("car");
    }
}

class Bike extends Vehicle {
    public void printSound() {
        System.out.print("bike");
    }
}

public class Test {
    public static void main(String[] args) {
        Vehicle v = new Car();
        Bike b = (Bike) v;

        v.printSound();
        b.printSound();
    }   
}

我的问题是:为什么这会导致运行时错误而不是编译错误?编译器不应该知道'v'已经是'Car'并且不能转换成'Bike'吗?

【问题讨论】:

    标签: java


    【解决方案1】:

    理论上,编译器有可能对自己说:“v 是局部变量,它被分配为 Car。在尝试强制转换为 Bike 之前绝不会这样做更改其值,Car 无法成功转换为Bike。因此,这是一个错误。"

    但是,我知道没有 Java 编译器可以为您进行这种分析。这真的只在最简单的情况下才值得。相反,行为是编译器看到了转换,并说明可以将Vehicle 转换为Bike,因此它允许这样做。

    一般来说,这就是强制转换的意思:它告诉编译器即使这个赋值可能会失败,但你很确定它不会。作为允许代码编译的交换,您承担了运行时异常的风险。

    【讨论】:

      【解决方案2】:

      从超类转换可能会起作用,因此是允许的(在编译期间)。不允许从完全不同的类进行强制转换,例如:

      Integer a = 1;
      String b = (String)a; // compile error
      String b = (String)(Object)a; // runtime error
      

      【讨论】:

        【解决方案3】:

        对于

        R r = /* some code to initialize "r" */
        T t = (T) r;
        

        Java 语言规范 说:

        如果R是普通类(不是数组类):

        • 如果 T 是类类型,则 R 必须是与 T 相同的类或 T 的子类,否则会引发运行时异常。
        • 如果 T 是接口类型,则 R 必须实现接口 T,否则将引发运行时异常。
        • 如果 T 是数组类型,则会引发运行时异常。

        【讨论】:

        【解决方案4】:

        对象的类型转换发生在运行时,因此编译器无法识别它

        【讨论】:

          【解决方案5】:

          没有。 vVehicle 并且可以将其转换为 Bike。找出每个对象的实际运行时类型并不是编译器的工作(尤其是因为有时这是不可能的)。

          【讨论】:

            【解决方案6】:

            Java 的语义表明这一定会导致运行时错误。在这种情况下,可以查看代码并发现它肯定会在运行时抛出错误,但编译器如何知道 ClassCastException 不是您想要的?

            像 IntelliJ 和 Eclipse 这样的编辑器可以(并且确实)注意到这些类型的错误并警告您,但是 Java 的规则说这是必须编译的合法代码。

            【讨论】:

              【解决方案7】:

              这是一个运行时错误,因为您已经将变量 v 定义为 Car。您无法将Car 转换为Bike

              编译器不会检查这种赋值,因为编译器通常不检查语义。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2016-07-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多