【问题标题】:Cast to unimplemented interface compiles转换为未实现的接口编译
【发布时间】:2015-02-23 07:25:22
【问题描述】:

我不确定我是否理解下面第 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,但是Device和Talkable是无关的,line1怎么可能合法?

【问题讨论】:

    标签: java class interface reference


    【解决方案1】:

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

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

    如果 S 是类类型:

    • 如果 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 的子类也可能)。

    在您的情况下,java.lang.ClassCastException 将在运行时抛出,因为 Device 无法转换为 Talkable。但在程序执行之前,编译器允许强制转换,因为可能存在实现TalkableDevice 的子类。

    【讨论】:

      【解决方案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)

      【讨论】:

      • 嗯,我不知道。那么,您是说即使 Phone 没有扩展 Device,第一行仍然会通过编译器?
      • 为什么(Number) "" 会失败?
      • @August 编译器知道字符串不可能是Number。但是Device可能Talkable
      • 到一个点。例如,您不能在不相关的类之间进行转换。
      • 不,这是因为String 是最终的,所以没有实例可以实现Numberdocs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.5.1
      【解决方案3】:

      第 1 行将引发运行时异常。如果转换可以成功完成,编译器不会在编译时检查。这就是为什么有时建议先使用instanceof 运算符检查这一点的原因。

      一般情况下,您始终可以将A 类型的变量x 强制转换为任何接口C,因为可能存在类B extends A implements C,或类B implements A, C

      对于将类A 的变量x 转换为任何类D 时,情况并非如此,因为不能存在子类E extends A, D,因为一个类不能扩展多个类。

      【讨论】:

        【解决方案4】:

        实际上,在第一行代码明确地“告诉”编译器右侧的对象是左侧类型的对象(这称为type casting)。这在编译时对 Java 中的任何两种类型都有效,但如果类型不相关,则会出现运行时错误(将抛出 Exception)。

        在第二行,所做的在编译时和运行时都是有效的,因为Phone 是它扩展和/或实现的任何类型,所以实际上,Phone 是 Talkable(和 Device) .

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-07-31
          • 2019-07-26
          • 1970-01-01
          • 1970-01-01
          • 2015-04-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多