java.lang.ClassException:AはBにキャストできません

私はこのコードを実装しました:

class A {
    //some code
}
class B extends A {
   //some code
}

class C {
    public static void main(String []args)
    {
        B b1 = (B) new A();
        A a1 = (B) new A();
    }
}

Both of these lines, when compiled separately, compile fine,but give runtime error with java.lang.ClassException: A cannot be cast into B.

なぜそれらはうまくコンパイルされますが、ランタイムエラーが発生しますか?

10
真剣に、これは基本的なOOPです。しかし、人々はそれを気にしないように見え、ネットで広く解説されているときには、回答を投稿してアップヴォートする方が好きです。
追加された 著者 Luiggi Mendoza,
古典的な例を考えてみましょう:犬は動物ですか? はい動物は犬ですか? たぶん。しかし必ずしもそうではありません。キャストによって、あなたは間違いを犯さないことを信頼するようにコンパイラに指示しています。しかし、実行時には、実際に自分が行っていることが分からないため、プログラムがクラッシュします。
追加された 著者 Maroun,
A のインスタンスは B とは関係がないためです。それはランタイムチェックです。
追加された 著者 Brian Roach,

13 答え

それが実行時に失敗する理由は、オブジェクトがBではないということです。それはAです。 some 一方、Bとしてキャストすることはできません。

コンパイラは、あなたのAオブジェクトに起こったすべてを分析することはできません。例えば。

A a1 = new B();
A a2 = new A();

B b1 = (B) a1;   //Ok
B b2 = (B) a2;   //Fails

コンパイラはあなたのAオブジェクトが実際にBにキャスト可能かどうか確信していません。上の例では、最後の2行はOKだったと思います。しかし、実際にプログラムを実行すると、 a2 がBではないことがわかります。これはAのみです。

7
追加された

A 型の参照の下で、 A を拡張する A クラスまたはクラスのオブジェクトを格納できることを理解する必要があります。コード> B 。

それで、

A a = new B();

a 参照の下にあるオブジェクトは B クラスのインスタンスなので、 B b のようにもっと正確な参照に何らかの形で格納することが可能です。だからこのように試してみましょう:

B b = a;//Type mismatch error

そのようなコードでは、この種の状況を防ぐために、コンパイル時に型が一致しません<�:code>エラーが発生します:
私たちは持っていると言います

  • class B1 extends A and
  • class B2 extends A

A a = new B1()を作成しました。コンパイラが B1 b = a型不一致エラーをスローしなかった場合、 B2 b = a B2 とは関係のない B1 のインスタンスがあります。

潜在的な型の不一致を認識していることをコンパイラに伝えるために、明示的に目的のクラスにキャストを使用する必要があります

B b = (B) a;

コンパイル時に A が可能なクラスへの参照 A のキャストが可能です。


あなたのコードでは、

B b1 = (B) new A();
A a1 = (B) new A();

new 演算子が A 型の参照を返すように new A()演算子がオブジェクトを作成したのと同じ型の参照を返すことを知る必要があります。 >そう

B b1 = (B) new A();

実際には

A tmp = new A();
B b1 = (B) tmp;

問題は、その派生クラスを参照して、あるクラスのオブジェクトを格納できないということです。どうして?その派生クラスに、そのオブジェクトクラスに似ていない新しいメソッドがあれば

class A {
   //some code
}

class B extends A {
    private int i;
    public void setI(int i){
        this.i=i;
    }
}

以降

B b = (B)new A();

b.setI(42); を呼び出そうとしますか?それは可能でしょうか?いいえ、クラスAのインスタンスにはメソッド setI がなく、idがあってもこのメソッドで使用される int i フィールドはありません。

これは、(B)new A();java.lang.ClassCastException をスローする理由です。

6
追加された
どういたしまして :)
追加された 著者 Pshemo,
素晴らしい答え!どうもありがとう。
追加された 著者 Ozil,

compiler が意味するのは、 expression のコンパイル時の型だけです。

の実行時タイプについては仮定していません。

http://docs.oracle .com/javase/specs/jls/se7/html/jls-5.html#jls-5.5.1

本当の問題になる

AをBにキャストできません BをAにキャストすることはできません。マンゴーを持っている場合はフルーツがあります。フルーツを持っている場合は、マンゴーを持っています。

2
追加された
A a1 = (B) new A();

AB ではないためです。

コンパイル時間は、実行時に AB になることを確かめるコンパイラーを明示的にキャストし、明示的に保証しているために機能します。

2
追加された

BがAを拡張するとき、AのすべてのメソッドおよびプロパティがBにも存在することを意味します。

あなたは今までBをAにキャストできます

AをBにキャストすることはできません。

アプリケーションでキャストするのは本当に気にする必要があります。

2
追加された

あなたがBがAを伸ばすと言うと、AはBの父になります 今技術的には、Bはすべてのcharecteristics とそれ自身の 一方、Aはそれ自体の特徴しか持たない

if you say convert A into B and assign to B, that is ok but if you say cast A into B and assign to A, thats not possible as A here does not know extra charecteristics present in B.

これらは実行時に発生するため、実行時エラーが発生します。

2
追加された

以下はコンパイル時のキャストです -

A a = new B();

このような静的キャスティングは、コンパイラがBが-aであるという事実を認識しているので、コンパイラによって暗黙的に実行される。

次はコンパイルされません -

B b = new A();

コンパイラはAがBでないことを知っているため、ここではコンパイル時のキャストは行いません。

コンパイルに続いて -

B b = (B) new A();

それはダイナミックキャスティングです。 (B)では、実行時にキャストを行うことをコンパイラに明示しています。また、実行時にキャストを実行しようとしたときにCCEが取得されますが、実行できず、CCEがスローされることがわかります。

このようなことをするとき(またはそれをしなければならないとき)、実行時にCCEが発生しないようにする責任がコンパイラではなくなります。

1
追加された

キャスティングが終わったときと関係があります。あなたはコンパイラーにこう言います。「ねえ、それを心配しないで、これは私が言うことです。問題があれば、実行時に私と一緒に持ち上げてください」

基本的に、コンパイラはあなたのことをあなたに任せています。明示的に何かをキャストすると、コンパイラはチェックを行いません。実行すると、プログラムはキャストしようとしますが失敗すると、エラーが表示されます。

1
追加された

私はコンパイル部分についてはわかりませんが、私はランタイムエラーを説明することができます。

BはクラスAのすべてのオブジェクトもタイプAのオブジェクトであることを意味します。もう一方の方法は真ではありません。

Aと 'Mammal'、Bと 'Cow'を比較してください。牛は常に哺乳動物ですが、すべての哺乳動物が牛ではありません。

1
追加された

B A であることを意味します。もの。

反対は間違っています。 A B ではありません。したがって、 AB にキャストすることはできません。

このように考えてください。 AAnimal です。 BBee です。 Bee は動物ですか?はい、そうです。動物の蜂は?そうではありません。例えば、犬は動物ですが、間違いなく蜂ではありません。

0
追加された

It's simple. Think that when you are extending you have to use is a

B `is a` A
A `is not` B

もっと現実的な例

class Animal{
}

class Dog extends Animal{
}

class Cat extends Animal{
}

犬の IS A 動物 動物は必要な犬(例:猫は犬ではなく、猫は動物です)は動物 IS

実行時例外が発生しているため、実行時にその動物が犬ではないことがわかります。これはダウンキャスティングと呼ばれ、何をしようとしても安全ではありません。

0
追加された

AB の親要素であるためです。 A の機能は B 拡張されていますが、元の機能は A です。したがって、 B は実際に A にキャストできますが、その逆はできません。

新しいメソッドを B に追加した場合は、 newMethodInB()としましょう。そのメソッドを A というインスタンスの変数 B で呼び出そうとすると(キャストが働いたとします)、何を期待しますか?コードが A に存在しないため、間違いなくエラーが発生します。

0
追加された

なぜなら、一部のAは実際にBになることができるから、Aのためにはうまくいくかもしれないからです。明示的なキャストを書くことによって、この特定のAが実際に有効なBであることを保証します。ただし、これは当てはまりません。

A justA = new A();
A anAThatIsAlsoAValidB = new B();//implicit cast to supertype

B b1 = (A) anAThatIsAlsoAValidB ;//Cast an A into a B. At runtime, this will work fine! Compiler allows casting A into B.
B b2 = (A) justA;//Cast an A into a B. At runtime, this won't work. Compiler has/uses no more info than above.

コンパイラが実際にその型について知らない理由は次のとおりです。

com.example.ThridPartyType obj = new com.example.ThridPartyType();
B b = (B) obj.getSomeA(); 
// getSomeA() returns A and that is all the compiler knows.
// Depeding on the implementation of "ThridPartyType::getSomeA()" the A returned may or may not actually also be a valid B. 
// Hence, if the cast works or not will only be known at runtime. If it doesn't, the Exception is thrown.
0
追加された