我正在考虑使用Java进行转换,特别是使用接口进行转换。假设我有一个接口I
,它定义了一个方法跳转,即:
interface I{
public void jump();
}
另外假设我有3个其他类,A
,B
和C
。 A
实施I
。 B
没有。但是,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编译器如何工作以及它们的局限性的一些文献的方向吗?
答案 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引用的实际对象不会如此本地化,因此编译时间可以确定。因此选择不使编译器过于智能化而不能解决实际问题。