Java Silver SE11の問題を解いていて継承とオーバーライドに関する問題を間違えるので備忘録として残す。
大事なのは何の型で宣言されて、何のインスタンスを生成しているか。
メソッドはどのようなアクセス修飾子が付与されているか。
public class Main {
public static void main(String[] args) throws Exception {
//case A
Super superClass = new Sub();
//case B
// Super superClass = new Super();
Sub subClass = new Sub();
//code 1
// subClass = superClass;
//code 2
// subClass = (Sub)superClass;
//code 3
// superClass = subClass;
superClass.print();
subClass.print();
}
}
class Super{
//case C privateで修飾
//case D staticで修飾
void print(){
System.out.println("Super");
}
}
class Sub extends Super{
//case D staticで修飾
void print(){
System.out.println("Sub");
}
}
それぞれの実行結果がどうなるか。
-
case Aの場合
-
code 1の時
サブクラス型の変数subClassにスーパークラス型の変数superClassを代入しているためコンパイルエラー -
code 2の時
スーパークラス型の変数superClassはSubクラスのインスタンス生成しているため、ダウンキャストされて代入される。実行結果はオーバーライドされたメソッドが優先されるので「Sub Sub」 -
code 3の時
スーパークラス型の変数superClassにサブクラス型の変数subClassを代入しているため自動的にアップキャストされ、実行結果も同様にオーバーライドされたメソッドが優先されて「Sub Sub」 -
case Bの場合
-
code 1の時
case Aの場合と同様にコンパイルエラー -
code 2の時
明示的にキャストしているためコンパイルエラーは起こらない。しかし、スーパークラス型の変数superClassはSuperクラスのインスタンスを生成しており、サブクラスの差分を持たないため、ClassCastExceptionがスローされる(実行時エラーが起きる) -
code 3の時
case Aの場合と同様にアップキャストされ、実行結果は「Sub Sub」 -
case Cの場合
-
スーパークラスであるSuperクラスのprintメソッドがprivateで修飾されると、オーバーライドされているとみなされず、生成されているインスタンスに関わらず、変数の型のprintメソッドが実行される。
-
case Dの場合
-
両方のprintメソッドがstaticで修飾された場合、変数の型のprintメソッドが実行される。
-
staticで修飾する場合は両方のメソッドを修飾しないとコンパイルエラーになる。