接口中的Java转换


75

有人可以向我解释一下,编译器在第一次强制转换中不会抱怨,而在第二次强制转换中会抱怨吗?

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

8
通过运行此命令,您将遇到ClassCastException,这是一个RuntimeException
Buhake Sindi

4
@BuhakeSindi你错了
Andremoniy 2013年

2
@BuhakeSindi OP表示编译器向我抱怨说您没有机会运行此程序。
emory

@emory,即使他可以通过修复存在编译器错误的项目来使其进行编译,但该行上面的行也会引起ClassCastException
Buhake Sindi

1
@BuhakeSindi您错了,因为您说不应该说的话。水很湿。但是在这种情况下谈论这个问题是错误的。好?显然,发问者是知道的,因为他做了一个实验。
2013年

Answers:


148

进行o1和转换o3(I2),您告诉编译器该对象的类实际上是其声明类型的子类,并且该子类实现I2

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

如果您使用C1final,编译器也会抱怨:

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

1
“整数是最终的,所以o3不会成为接口I2的机会。”这种形式的确很错误。不是意义,而是措辞。
Powerslave 2013年

1
@WilQu我不是在抱怨拼写错误,而是答案的措辞。如果您在下面看一眼,您会看到艾蒂安(Etienne)对同一事物的措辞更加清晰。你可以misunderstandable,从而误导因为你没有提到(例如),其Integer是最后的(这是显而易见的,我和你,但可能不是每个人)和“没有成为一名接口机会”部分不没有携带太多信息;实际上,相关信息隐藏在第二句中。甚至可能认为final类不能实现接口,这是不正确的。
Powerslave

@Powerslave感谢您的评论,我再次编辑了答案。我试图添加更多的解释,希望它不会使我的答案更加混乱。
WilQu

@WilQu太好了!原来是一个很好的解释:)
Powerslave

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



15

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

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

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

在这种情况下,Integer和和I2根本不相关,因此会发生编译时错误。另外,因为Integerfinal,所以Integer和之间没有关系I2

I2并且I1由于两者都是标记界面(没有合约)而可能相关。

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

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

So1并且TI2

希望这可以帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.