3

建物とコードを拡張するクラス Cottage を想像してみてください

Building building = new Building();
Cottage cottage = (Cottage)building;

ここで、 Java の継承の性質を考慮すると、 BuildingをCottageにキャストできないことは完全に理にかなっていますが、(私にとって) 理にかなっていないのは、これがコンパイルされることです。コンパイルして実行時にClassCastExceptionをスローするのはなぜですか?

実際にプログラムを実行する前に、 Building が Buildingオブジェクトへの参照であることは明らかではないでしょうか。

このような一般的な質問であるため、これが重複している可能性があることはわかっています:)しかし、なぜコンパイルするのかという質問に対する答えが見つかりませんでした:)

EDIT2私はここで素晴らしい答えを受け入れました(その下の議論は言うまでもありません:))が、コンパイルエラーではなく実行時エラーが発生するJavaキャストで受け入れられた答えが最も興味深い...

EDIT IllegalCastExceptionを編集し、正しいClassCastExceptionを配置しました

4

3 に答える 3

10

これは、参照が参照しているオブジェクトをコンパイラが認識していないためBuildingです。

したがって、以下のケースでは、基本クラスの参照があり、サブクラスのオブジェクトを指しています: -

Building building = new Cottage();
Cottage cottage = (Cottage)building;

それは完全にうまくいくでしょう。したがって、それが有効なキャストであるかどうかは、完全に実行時の決定です。したがって、コンパイラはそのためにエラーをスローしません。

実際にプログラムを実行する前に、 building が Building オブジェクトへの参照であることは明らかではありませんか?

いいえ、絶対に違います。参照されているオブジェクトのタイプは、実行時までわかりません。コンパイラは常に参照型をチェックすることを常に覚えておいてください。実際のオブジェクト タイプは実行時にチェックされます。

この概念はポリモーフィズムと呼ばれ、同じ参照型を使用してさまざまなサブタイプのオブジェクトを指すことができます。あなたはそれをグーグルすることができ、読むための多くのリソースを得るでしょう.

于 2013-01-22T21:08:43.170 に答える
3

キャストの機能の一部は、コンパイラを黙らせることです。キャストしているオブジェクトが何であるかをコンパイラよりもよく知っていると言っています。キャストが正確でない場合、例外が発生します。

おそらく、コンパイラーがオブジェクトが指しているオブジェクトを追跡し、参照が妥当かどうかを判断していると思います。コンパイラはそれほどスマートではなく、簡単にだまされます。次のスニペットを参照してください。

    int i = 1;
    System.out.println((Number)i);        
    Object o = i;
    System.out.println((String)i); // won't compile (primitive-to-ref-type cast)
    System.out.println((String)o); // compiles (thanks to autoboxing)

コンパイラは、プリミティブと参照型の間の変換を防止することのみを考慮します。

于 2013-01-22T21:10:53.763 に答える
2

建物(スーパークラス)参照を使用してコテージ(サブクラス)オブジェクトを作成することを検討してください

Building b= new Cottage();
Cottage c = (Cottage) b;

上記のコードは正当であるため、コンパイラはc実行時に参照変数が参照するオブジェクトを認識しないため、コンパイラはエラーをスローしません。

コンパイルしてから実行時に IllegalCastException をスローするのはなぜですか?

ところで、スーパークラス オブジェクトをIllegalCastExceptionではなくサブクラスにキャストしようとすると、ClassCastExceptionがスローされます。

于 2013-01-22T21:10:40.467 に答える