接口中的 Java 转换

2022-08-31 12:35: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 !!
     }
}

答案 1

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

该类是最终的,因此不能是 的子类的实例:编译器知道你在撒谎。 但是不是最终的,因此可能是实现 的子类型的实例。Integero3IntegerC1o1C1I2

如果你做 final,编译器也会抱怨: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
     }
}

答案 2

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