接口中的Java转换

geo*_*geo 74 java casting interface

有人可以向我解释一下编译器在第一次投射时不会抱怨,但是在第二次投射中是否会抱怨?

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 !!
     }
}
Run Code Online (Sandbox Code Playgroud)

Wil*_*lQu 145

当你施放o1o3(I2),你告诉编译器,这个类的对象实际上是其宣称的类型的子类,且该子类实现I2.

Integer班是最后的,所以o3不可能是一个子类的实例Integer:编译器知道你在说谎.C1但是不是最终的,因此o1 可以C1该实现的子类型的实例I2.

如果你做了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
     }
}
Run Code Online (Sandbox Code Playgroud)


mab*_*aba 35

根据JLS第5章

5.5.1.参考类型铸造

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

如果S不是最终类(第8.1.1节),那么,如果存在T的超类型X和S的超类型Y,则X和Y都是可证明的不同参数化类型,并且X的擦除和Y相同,发生编译时错误.

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

如果S是最终类(第8.1.1节),那么S必须实现T,否则会发生编译时错误.


Eti*_*ret 23

那是因为上课Integer是最终的而C1不是.因此,Integer对象不能实现I2,而C1对象可以是C1实现I2的C1子类的实例.


Buh*_*ndi 15

根据JLS 5.5.1 - 参考类型转换,规则适用:

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

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

在这种情况下,IntegerI2不相关的任何方式,所以发生编译时间错误.另外,因为Integerfinal,Integer和之间没有关系I2.

I2I1由于两者都是标记界面(没有合同),因此可以相关.

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

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

So1TI2.

希望这可以帮助.