强制转换为未实现的接口编译

2022-09-04 06:00:03

我不确定我是否理解下面第 1 行中的代码?

interface Talkable{ }
class Device{}
class Phone extends Device implements Talkable{}


Talkable d = (Talkable) new Device(); //line 1
Talkable p = new Phone(); //line 2

我理解line2,因为Phone实现了Talkable,但设备和Talkable是无关的,Line1怎么能合法呢?


答案 1

编译器接受这一点的原因在 JLS 第 5.5.1 节(相关部分以粗体显示)中进行了解释:

给定编译时引用类型 S(源)和编译时引用类型 T(目标),如果由于以下规则未发生编译时错误,则存在从 S 到 T 的强制转换转换。

如果 S 是类类型:

  • 如果 T 是类类型,则任一|S|<: |T|或|T|<: |S|.否则,将发生编译时错误。

此外,如果存在 T 的超类型 X 和 S 的超类型 Y,使得 X 和 Y 都是可证明不同的参数化类型 (§4.5),并且 X 和 Y 的擦除相同,则会发生编译时错误。

  • 如果 T 是接口类型:

    • 如果 S 不是最终类 (§8.1.1),则如果存在 T 的超类型 X 和 S 的超类型 Y,使得 X 和 Y 都是可证明不同的参数化类型,并且 X 和 Y 的擦除是相同的,则会发生编译时错误。

      否则,强制转换在编译时始终是合法的(因为即使 S 不实现 T,S 的子类也可能实现)。

在您的情况下,将在运行时抛出 a,因为无法转换为 。但是在程序执行之前,编译器允许强制转换,因为可能有一个实现的子类。java.lang.ClassCastExceptionDeviceTalkableDeviceTalkable


答案 2

实际上,在Java中,将一种相关类型转换为另一种相关类型是完全有效的(即使转换没有多大意义)。如果类型不兼容,您将在运行时收到错误。

例如:

    public static void main(String[] args) {
        String s = (String) new Object();
        System.out.println(s.intern());

    }

编译正常,但在运行时给出Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String at Sample.main(Sample.java:5)