接口中的 Java 强制转换

Posted

技术标签:

【中文标题】接口中的 Java 强制转换【英文标题】:Java casting in interfaces 【发布时间】:2013-04-17 16:17:05 【问题描述】:

有人可以向我解释一下编译器如何在第一次强制转换时不抱怨,但在第二次转换时却抱怨吗?

interface I1  
interface I2  
class C1 implements I1  
class C2 implements I2  

public class Test
     public static void main(String[] args)
        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 !!
     

【问题讨论】:

运行这个,你会遇到ClassCastException,这是一个RuntimeException @BuhakeSindi 你错了 @BuhakeSindi OP 说编译器向我抱怨说你没有机会运行它。 @emory,即使他可以通过修复有编译器错误的项目来编译它,它上面的行也会导致ClassCastException @BuhakeSindi 你错了,因为你说了你不应该说的话。水是湿的。但在这种情况下谈论这个问题是错误的。好的?显然,提问者知道这件事是因为他做了一个实验。 【参考方案1】:

当您将o1o3 转换为(I2) 时,您告诉编译器该对象的类实际上是其声明类型的子类,并且该子类实现了I2

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

如果你将C1设为final,编译器也会报错:

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
     

【讨论】:

"整数是最终的,所以 o3 不可能是接口 I2" 这在这种形式中是非常错误的。不是意思,而是措辞。 @WilQu 我不是在抱怨错字,而是在抱怨答案的措辞。如果你看看下面,你会发现艾蒂安对同一件事的措辞更加清晰。你的可能会被误解,因此会产生误导,因为你没有提到(例如)Integer 是最终的(这对我和你来说很明显,但可能不是每个人都知道)和 “没有机会成为接口”部分不携带太多信息;事实上,有问题的信息隐藏在第二句话中。人们甚至可能认为final 类不能实现接口,这是不正确的。 @Powerslave 感谢您的 cmets,我再次编辑了我的答案。我试图添加更多解释,希望它不会使我的答案更加混乱。 @WilQu 太棒了!原来是一个非常好的解释:)【参考方案2】:

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

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

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

如果 T 是类类型,那么 |S| <:>

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

在这种情况下,IntegerI2 在任何方面都不相关,因此会发生编译时错误。另外,因为Integerfinal,所以IntegerI2 之间没有关系。

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

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

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

So1TI2

希望这会有所帮助。

【讨论】:

以上是关于接口中的 Java 强制转换的主要内容,如果未能解决你的问题,请参考以下文章

关于java中任意对象强制转换为接口类型的问题

java,Object类型可以转换为接口吗?

Java中的强制类型转换是如何转换的?

Java中的强制类型转换是如何转换的?

java中的强制类型转换

java 里 可以把一个父类强制转换成一个子类 不能把一个子类强制转换成一个父类? 对吗?