在接口中进行Java转换

有人可以请我解释一下,编译器在第一次投射时没有抱怨,但是在第二次投诉呢?

interface I1 { } interface I2 { } class C1 implements I1 { } class C2 implements I2 { } public class Test{ public static void main(){ C1 o1 = new C1(); C2 o2 = new C2(); Integer o3 = new Integer(4); I2 x = (I2)o1; //compiler does not complain I2 y = (I2)o3; //compiler complains here !! } } 

当用(I2) o3 o1o3时,告诉编译器该对象的类实际上是其声明types的一个子类,而这个子类实现了I2

Integer类是final的 ,所以o3不能是Integer子类的一个实例:编译器知道你在说谎。 然而C1不是最终的,所以o1 可能是实现I2C1子types的一个实例。

如果你做C1最后,编译器也会抱怨:

 interface I1 { } interface I2 { } final class C1 implements I1 { } class C2 implements I2 { } public class Test{ public static void main(){ C1 o1 = new C1(); C2 o2 = new C2(); Integer o3 = new Integer(4); I2 y = (I2)o3; //compiler complains here !! I2 x = (I2)o1; //compiler complains too } } 

根据JLS第5章

5.5.1。 参考typesCasting

给定编译时引用typesS(源)和编译时引用typesT(目标),如果由于以下规则而没有发生编译时错误,则从S存在到T的转换转换。 如果T是一个接口types:

如果S不是最终类(§8.1.1),那么如果存在T的超typesX和S的超typesY,使得X和Y都是可certificate的不同参数化types,并且X的删除和Y是一样的,会发生编译时错误。

否则,转换在编译时总是合法的(因为即使S没有实现T,也可能是S的一个子类)。

如果S是最后一个类(§8.1.1),那么S必须实现T,否则会发生编译时错误。

那是因为Integer类是final的, C1不是。 因此,一个Integer对象不能实现I2,而一个C1对象如果它是一个实现I2的C1子类的实例。

根据JLS 5.5.1 – 参考types铸造 ,该规则适用于:

  • 如果T是一个类types,则| S | <:| T |或者| T | <:| S |。 否则,会发生编译时错误。

    I2 y = (I2)o3; //compiler complains here !!

在这种情况下, IntegerI2无关的 ,所以会发生编译时错误。 而且,因为IntegerfinalIntegerI2之间没有关系。

I2I1可以是相关的,因为它们都是标记接口(没有合同)。

至于编译的代码,规则如下:

  • 如果S不是最终类(§8.1.1),那么如果存在T的超typesX和S的超typesY,使得X和Y都是可certificate的不同参数化types,并且X的删除和Y是一样的,会发生编译时错误。

So1TI2

希望这可以帮助。