4

特定の問題で奇妙な動作をする1つのJavaコンパイルシナリオに混乱しました。

A と B は別個のクラスであり、それらの間に関係がないため、以下のコードはコンパイル エラー (型をキャストできません) を返します。

        A a = new A();
        B b = new B();

        B b1 = (B)a;
        A a1 = (A)b;

同様に、リストとマップを互いにキャストすると、コンパイルエラーが発生するはずですが、そのようなエラーは発生しません。もちろん、実行時に ClassCastException が発生しています。

        List<String> listObj = new ArrayList<String>();
        Map<Integer,Float> mapObj = new HashMap<Integer,Float>();

        Map newMapObj = (Map) listObj;
        List newListObj = (List) mapObj;

この調整の理由は何でしょうか...

4

1 に答える 1

7

これは、MapListがインターフェイスであり、両方を実装するクラスを持つことができるためです。Java では多重継承ができないため、これはクラスには無効です。


そのようなユースケースでコンパイラが非常にばかげているように見えたとしても (このコンテキストではキャストが決して成功しないことは明らかであるため)、初期化コードを深く掘り下げることはあまり意味がありません。その参照に:

List<String> someOtherList = getSomeOtherList();
List<String> listObj = someOtherList != null ? someOtherList : new ArrayList<String>();

これにより、コンパイラがこの行の後にどのようなものにListなるかを知ることができなくなります。listObj

あなたの単純な例でも、コンパイラは、の最初の宣言listObjとキャストの試行の間に、その変数への他の割り当てがないことを追跡する必要があります(それlistObjが間違いなく であると推測できるようにArrayList)。このような追跡は、代入とキャストの間に他のコード行が配置されると、苦痛から不可能になる可能性があります。


しかし、そのようなコンパイラの制限がイライラする可能性があることに同意します。以下がコンパイルされないという事実に時々悩まされます。

final int i;
try {
    i = Integer.parseInt("someString");
} catch (NumberFormatException e) {
    i = -1;
}

...「変数 'i' が既に割り当てられている可能性がある」ため、これは明らかに不可能です。しかし、コンパイラは実際にはtryブロックの内容を気にしません。その代入の後にコード行によって a がスローされる可能性があると想定します。NumberFormatExceptionそのためi宣言できませんfinal

于 2013-02-05T08:19:10.477 に答える