Javaでは、あるクラスのオブジェクトから別のクラスのオブジェクトへは、原則としてキャストを行うことはできません。
それは、あるクラスと別のクラスのフィールドやメソッドが一致していないからです。そのため、そのまま同じクラスとして扱うことができないからです。
┏ClassA━━┓ ┏ClassB━━┓ ┃ ┃ ┃ ┃ ┃ ┃public ┃ ┃public ┃ ┠─○a ←────── ┃ ┠─○v ┃ ┠─○b a b c() d()と ┃ ┠─○w ┃ ┠─○c() v w x() y()は ┃ ┠─○x() ┃ ┠─○d() 一致しない ┃ ┠─○y() ┗━━━━━┛ ┗━━━━━┛
あるクラスから別のクラスへのオブジェクトのキャストは不可能と書きましたが、例外があります。サブクラスとスーパークラスの間のキャストは可能です。
ここではまずは、サブクラスからスーパークラスへのオブジェクトのキャストを扱います。これは問題なく行えます。
なぜならば、サブクラスの中に、スーパークラスのフィールドとメソッドが全て含まれているからです。
┏SubClass━━━━┓ ┏SuperClass━┓ ┃┏SuperClass━┓┃ ┃ ┃public ←─── ┃┃ ┃┃public ┃ ┠─○a aとb()が ┃┃ ┠──○a ┃ ┠─○b() あるので ┃┃ ┠──○b() ┗━━━━━━┛ 同じと ┃┗━━━━━━┛┃ みなせる ┃ ┃public ┃ ┠─○x ┃ ┠─○y() ┗━━━━━━━━┛
サブクラスからスーパークラスにキャストしたオブジェクトは、フィールドはスーパークラスのものが使われます。
また、メソッドは、オーバーライドされていればサブクラスのものが、されていなければ通常通りにスーパークラスのものが使われます。
┏SubClass━━━━━━━━┓ ┃┏SuperClass━┓ ┃ ┃┃ ┃public ┃ ┃┃ ┠─★a ┠─○a ┃┃ ┠─○b() ┠─★@Override b() ┃┃ ┠─★c() ┃ ┃┗━━━━━━┛ ┃ ┗━━━━━━━━━━━━┛
package sample; public class SuperClass { public int no = 1; public int getNo() { return no; } }
package sample; public class SubClass extends SuperClass { public int no = 9; @Override public int getNo() { return no * 2; } }
SubClass subClass = new SubClass(); System.out.println(subClass.no); // 「9」と出力 System.out.println(subClass.getNo()); // 「18」と出力 SuperClass superClass = subClass; System.out.println(superClass.no); // 「1」と出力 System.out.println(superClass.getNo()); // 「18」と出力
スーパークラスからサブクラスへのオブジェクトのキャストは、実行時エラーになる場合と、そうでない場合があります。
まず、エラーになる場合です。以下の例では、スーパークラスには、サブクラスで拡張されたフィールドやメソッドが含まれていません。そのため、そのまま使うことができず、エラーが発生します。
// 実行時にエラーになる java.lang.ClassCastException SuperClass superClass = new SuperClass(); SubClass subClass = (SubClass)superClass;
┏SubClass━━━━┓ ┃┏SuperClass━┓┃ ┏SuperClass━┓ ┃┃ ┃┃public ←──── ┃ ┃public ┃┃ ┠──○a xとy()が ┃ ┠─○a ┃┃ ┠──○b() ないので ┃ ┠─○b() ┃┗━━━━━━┛┃ 同じと ┗━━━━━━┛ ┃ ┃public みなせない ┃ ┠─○x ┃ ┠─○y() ┗━━━━━━━━┛
次にエラーにならない場合です。以下の例では、参照先のインスタンスがサブクラスのものなので、エラーは発生しません。
ここで重要なのは、キャストしても変数の中身の情報が失われるわけではないということです。
// 実行時にエラーにならない SubClass subClass1 = new SubClass() SuperClass superClass = (SuperClass)subClass1; SubClass subClass2 = (SubClass)superClass;
┏Sub ━━━┓ ┏Sub ‥‥‥┓ ┏Sub ━━━┓ ┃┏Super ┓┃ :┏Super ┓: ┃┏Super ┓┃ ┃┃ ┃┃public ←:┃ ┃:public ←┃┃ ┃┃public ┃┃ ┠──○a :┃ ┠──○a ┃┃ ┠──○a ┃┃ ┠──○b() :┃ ┠──○b() ┃┃ ┠──○b() ┃┗━━━┛┃ :┗━━━┛: ┃┗━━━┛┃ ┃ ┃public : :public ┃ ┃public ┃ ┠─○x : :─○x ┃ ┠─○x ┃ ┠─○y() : :─○y() ┃ ┠─○y() ┗━━━━━┛ ┗‥‥‥‥‥┛ ┗━━━━━┛
メソッドの引数でクラスが指定されている場合は、そのサブクラスも全て利用することができます。
これは、サブクラスはスーパークラスの代わりに利用できるからです。
public void method(SuperClass sc) { }
SuperClass superClass = new SuperClass(); SubClass subClass = new SubClass(); method(superClass); // 問題なし method(subClass); // 問題なし