Java编译器和接口转换

时间:2016-02-18 18:27:41

标签: java interface casting

我正在考虑使用Java进行转换,特别是使用接口进行转换。假设我有一个接口I,它定义了一个方法跳转,即:

interface I{
    public void jump();
}

另外假设我有3个其他类,ABCA实施IB没有。但是,C扩展了B并实施了I

class A implements I {
   public void jump(){
      System.out.print("A is jumping");
   }
}
class B { } 
class C extends B implements I {
    public void jump(){
        System.out.print("C is jumping");
    }
}

现在,如果我尝试将A类型的对象分配给I,则没有问题,我甚至不需要演员。即:

I i = new A();

没关系,不需要施法。

据推测,这是因为编译器知道A实现了I.此外,如果我尝试这样做:

A mya = new A();
I i = mya;

没问题,即使mya可以引用A的子类。但AFAIK没问题,因为编译器知道A的每个子类都必须隐式实现jump方法,因此必须实现接口A

但是,如果我尝试将B类型的对象分配给I,那么我确实需要一个演员。 e.g。

B myb = new B();
I i = (I)myb;

大概这是因为编译器知道B没有实现I。但是,由于B可以引用实现I的子类,因此您可以转换为I。到现在为止还挺好。 现在这里是我的问题:如果我想要一个B类型的对象引用类型为C的对象(实现I)到I那么我们需要演员。这是为什么?例如。

B b = new C();
I myI = b; //Won't compile this needs a cast
I myI = (C)b; // This will compile
myI = (I)b; // This will also compile

为什么编译器不理解B指的是实现I的C

据推测,这与B可以引用实际上没有实现B的{​​{1}}的事实有关,但为什么编译器不知道呢?据推测,编译器仅限于每行可用的信息?它无法运行您的程序并看到I实际上指向b?如果这是正确的,有人可能会指出我关于Java编译器如何工作以及它们的局限性的一些文献的方向吗?

2 个答案:

答案 0 :(得分:5)

  

大概这是因为编译器知道B没有实现I,但是因为B可以引用一个实现I的子类,所以你可以转换为I。

不完全是。编译器将允许您根据需要投射B.这并不意味着您在运行时无法获得ClassCastException。 (你的代码这次会工作,但是编译器不会阻止你制作糟糕的演员表。)

  

为什么编译器不理解B指的是实现I的C?大概是因为B可以引用一个实际上并没有实现我的B,但为什么编译器不知道呢。

因为您在声明B

时告诉它将对象视为B b = new C();
  

据推测,编译器仅限于每行可用的信息?它无法运行您的程序,并且看到b实际上指向了c?

它可以访问其余代码。它只是做你告诉它要做的事情:将b视为班级B的对象。

答案 1 :(得分:-1)

在这种特殊情况下,编译器能够确定b实际上是指C的对象。但语言创建者选择不使编译器如此智能。

在实际场景中,b引用的实际对象不会如此本地化,因此编译时间可以确定。因此选择不使编译器过于智能化而不能解决实际问题。