接口中的Java转换

时间:2013-04-24 07:54:55

标签: java interface casting

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

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 !!
     }
}

4 个答案:

答案 0 :(得分:145)

当您使用o1转换o3(I2)时,您告诉编译器该对象的类实际上是其声明类型的子类,并且该子类实现了{{ 1}}。

I2类是 final ,因此Integer不能是o3的子类的实例:编译器知道你在撒谎。 Integer不是最终版,因此C1 可以是实现o1的{​​{1}}子类型的实例。

如果你让C1成为最终版,编译器也会抱怨:

I2

答案 1 :(得分:33)

根据JLS chapter 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,否则会发生编译时错误。

答案 2 :(得分:22)

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

答案 3 :(得分:15)

根据JLS 5.5.1 - Reference Type casting,规则适用:

  • 如果T是类类型,则为| S | &lt ;: | T |,或| T | <:| S |。否则,将发生编译时错误。

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

在这种情况下,IntegerI2以任何方式无关,因此会发生编译时错误。另外,因为IntegerfinalIntegerI2之间没有任何关系。

I2I1可以相关,因为它们都是标记界面(没有合约)。

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

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

So1TI2

希望这有帮助。