79

コンパイラが最初のキャストで文句を言わないが、2番目のキャストで文句を言う方法を誰かが私に説明できますか?

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

4 に答える 4

150

とをキャストするo1と、オブジェクトのクラスが実際には宣言された型のサブクラスであり、このサブクラスが を実装していることをコンパイラに伝えます。o3(I2)I2

Integerクラスはfinalであるため、のo3サブクラスのインスタンスにすることはできませんInteger。コンパイラは、あなたが嘘をついていることを知っています。C1ただし、最終的なものではないため、その implementsのサブタイプのインスタンスであるo1 可能性があります。C1I2

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
     }
}
于 2013-04-24T08:01:02.230 に答える
36

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 のサブクラスが T を実装している可能性があるため)。

S が最終クラス (§8.1.1) の場合、S は T を実装する必要があります。そうしないと、コンパイル時エラーが発生します。

于 2013-04-24T08:06:53.883 に答える
15

JLS 5.5.1 - 参照型のキャストによると、次のルールが適用されます。

  • T がクラス型の場合、|S| のいずれかです。<: |T|、または |T| <: |S|. そうしないと、コンパイル時エラーが発生します。

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

この場合、IntegerI2まったく関係がないため、コンパイル時エラーが発生します。また、Integerはであるため、 と の間にfinalは関係がありません。IntegerI2

I2両方がマーカーインターフェイスであるため、I1関連付けることができます(コントラクトはありません)。

コンパイルされたコードに関しては、ルールは次のとおりです。

  • S が最終クラス (§8.1.1) でない場合、T のスーパータイプ X と S のスーパータイプ Y が存在し、X と Y の両方が異なるパラメータ化された型であることが証明され、X の消去がと Y が同じ場合、コンパイル時エラーが発生します。

Sです。o1_ T_I2

お役に立てれば。

于 2013-04-24T08:06:37.107 に答える