在接口中进行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
o1
和o3
时,告诉编译器该对象的类实际上是其声明types的一个子类,而这个子类实现了I2
。
Integer
类是final的 ,所以o3
不能是Integer
子类的一个实例:编译器知道你在说谎。 然而C1
不是最终的,所以o1
可能是实现I2
的C1
子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 !!
在这种情况下, Integer
和I2
是无关的 ,所以会发生编译时错误。 而且,因为Integer
是final
, Integer
和I2
之间没有关系。
I2
和I1
可以是相关的,因为它们都是标记接口(没有合同)。
至于编译的代码,规则如下:
- 如果S不是最终类(§8.1.1),那么如果存在T的超typesX和S的超typesY,使得X和Y都是可certificate的不同参数化types,并且X的删除和Y是一样的,会发生编译时错误。
S
是o1
, T
是I2
。
希望这可以帮助。