ダウンキャスト - 継承 - 萌えJava超入門
クラスの継承

ダウンキャスト

継承関係にあるクラスはキャストできます。
下位のクラスへのキャストをダウンキャストといいます。

Dog dog = (Dog)animal;
class Dog extends Animal

目次

1. ダウンキャストとは

継承関係にあるクラスはキャスト(型変換)が可能です。
下位のクラス(サブクラス側)に変換することをダウンキャストといいます。

重要
 ダウンキャストは、
 プリミティブ型のキャストと同じように、
 インスタンスの前に (スーパークラス名)を付けます。
 ダウンキャストは、暗黙的に行えません。

ダウンキャスト 書式
  Animal animal = new Dog();
  Dog dog = (Dog)animal;
class Dog extends Animal

萌えJava超入門 萌えJava超入門
プリミティブ型のキャストと
同じ感じね。
萌えJava超入門



2. ダウンキャストの例


以下のサンプルでは、Animal_01クラスをスーパークラスにして、
Dog_61、Cat_61、というサブクラスを作りました。
Dog_61、Cat_61、のインスタンスを、Animal_01型の配列に代入しています。
これがダウンキャストです。

Animal_01.java(再出)
  //Animal_01.java

  public class Animal_01{

        protected static String = "生き物です。";
        protected String name;

        public Animal_01(){
            this.name = "no_name";
        }
        public Animal_01(String name){
            this.name = name;
        }
        public static void printGroup(){
            System.out.println(group);
        }
        public void printName(){
            System.out.println(name + "だぞ! ガオー!");
        }
  }

Dog_61.java(再出)
  //Dog_61.java
  public class Dog_61 extends Animal_01{
      public Dog_61(String name){
          super(name);
      }
      //以下オーバーライドしたメソッド
      @Override
      public void printName(){
          System.out.println(name + "だワン!");
      }

      //追加したメソッド
      public void printBow(){
          System.out.println(name + "は棒には当たらないワン!");
      }
  }

Cat_61.java(再出)
  //Cat_61.java
  public class Cat_61 extends Animal_01{
      public Cat_61(String name){
          super(name);
      }
      //オーバーライドしたメソッド
      @Override
      public void printName(){
          System.out.println(name + "なのにゃ!");
      }

      //追加したメソッド
      public void printKoban(){
          System.out.println(name + "は小判が欲しいのにゃ!");
      }
  }

萌えJava超入門
ダウンキャストして、
サブクラス独自のメソッドを
実行した例だ。
//Driver_71.java

public class Driver_71{

  public static void main(String[] args){
      Animal_01[] animalArray = new Animal_01[9];
      animalArray[0] = new Animal_01("ゴン太くん");
      animalArray[1] = new Animal_01("ふなっしー");
      animalArray[2] = new Animal_01("アニマル浜口");
      animalArray[3] = new Dog_61("ヨーゼフ");
      animalArray[4] = new Dog_61("パトラッシュ");
      animalArray[5] = new Dog_61("白いお父さん");
      animalArray[6] = new Cat_61("ニャース");
      animalArray[7] = new Cat_61("ドラえもん");
      animalArray[8] = new Cat_61("ニャンパス");

      for(int i=0; i<animalArray.length; i++){
          animalArray[i].printName();
      }
      //ここまでは Driver_61 と同じです。-----------------------------

      System.out.println("-- dog --");
      for(int i=3; i<6; i++){
          Dog_61 dog = (Dog_61)animalArray[i]; //ダウンキャスト
          dog.printBow(); //Dog_61クラス独自のメソッド

      }
      System.out.println("-- cat --");
      for(int i=6; i<9; i++){
          Cat_61 cat = (Cat_61)animalArray[i]; //ダウンキャスト
          cat.printKoban(); //Cat_61クラス独自のメソッド

      }

  }
}

萌えJava超入門 萌えJava超入門
これは前のページの
Driver_63と 同じ結果っすね!
コマンドライン
>cd ws
ws>javac -encoding UTF-8 Driver_71.java
ws>java Driver_71
-- animal --
ゴン太くんだぞ! ガオー!           printName
ふなっしーだぞ! ガオー!           printName
アニマル浜口だぞ! ガオー!         printName
ヨーゼフだワン!                    printName
パトラッシュだワン!                printName
白いお父さんだワン!                printName
ニャースなのにゃ!                  printName
ドラえもんなのにゃ!                printName
ニャンパスなのにゃ!                printName
-- dog --
ヨーゼフは棒には当たらないワン!    printBow
パトラッシュは棒には当たらないワン!printBow
白いお父さんは棒には当たらないワン!printBow
-- cat --
ニャースは小判が欲しいのにゃ!      printKoban
ドラえもんは小判が欲しいのにゃ!    printKoban
ニャンパスは小判が欲しいのにゃ!    printKoban


萌えJava超入門
実はこの方法は
ちょっと使いづらい。
次を見てくれ。


3. キャスト先のインスタンスでないとダウンキャストできない


重要
キャスト先のインスタンスでないとダウンキャストできない。

例えば、Animal_01のインスタンスは、Dog_61クラスや、Cat_61クラスにキャストできません。
Driver_71 で、 i=3; i<6; のように「狙い撃ち」していたのはこのためです。

萌えJava超入門 萌えJava超入門
まあ、
そうでしょうね。
萌えJava超入門
//Driver_72NG.java

public class Driver_72NG{

    public static void main(String[] args){
        Animal_01 animal = new Animal_01("アニマル浜口");;
        Cat_61 cat = (Cat_61)animal; //NGダウンキャスト
    }
}

コマンドライン
>cd ws
ws>javac -encoding UTF-8 Driver_72NG.java
ws>java Driver_72NG
Exception in thread "main" java.lang.ClassCastException:
   Animal_01 cannot be cast to Cat_61
        at Driver_72NG.main(Driver_72NG.java:7)


萌えJava超入門
え~、
Animal_01
キャンのっと ビー キャスト とぅ
Cat_61?
萌えJava超入門
つまり、
アップキャストしたインスタンスを
戻すときに使うってことね?
ダウンキャストする場合には、
目的のクラスにダウンキャストできるか確認する必要があります。

共通のスーパークラスを持つサブクラスを複数利用する場合には、
後述の「インターフェイス」を使う方法もご検討ください。
きれいに書けると思います。

萌えJava超入門
そう。
なのです。


4. instanceof 演算子でクラスを調べる


ダウンキャストがいまいち使いにくいのは、
アップキャストしたインスタンスが、目的のクラスにダウンキャストできるか判別する方法が必要だからです。
java.lang.ClassCastException をキャッチする方法も考えられますが、
事前に instanceof 演算子で、インスタンスのクラスを調べる方法もあります。

書式
boolean bool = 調べたい変数 instanceof クラス名;

instanceof 演算子は、変数が目的のクラスであるか調べる演算子です。
目的のクラスであれば true
そうでなければ false
を返します。

スーパークラスの配列に、アップキャストしたインスタンスを代入しているとき、
各要素を instanceof 演算子で評価すれば、 ClassCastException を回避できます。

萌えJava超入門
こういった使い方が
効率的に正しいのか
ちょっとよくわからない。
//Driver_73.java

public class Driver_73{

  public static void main(String[] args){
      Animal_01[] animalArray = new Animal_01[9];
      animalArray[0] = new Animal_01("ゴン太くん");
      animalArray[1] = new Animal_01("ふなっしー");
      animalArray[2] = new Animal_01("アニマル浜口");
      animalArray[3] = new Dog_61("ヨーゼフ");
      animalArray[4] = new Dog_61("パトラッシュ");
      animalArray[5] = new Dog_61("白いお父さん");
      animalArray[6] = new Cat_61("ニャース");
      animalArray[7] = new Cat_61("ドラえもん");
      animalArray[8] = new Cat_61("ニャンパス");

      for(int i=0; i<animalArray.length; i++){
          animalArray[i].printName();
      }
      //ここまでは Driver_61 と同じです。-----------------------------

      System.out.println("-- dog --");
      for(int i=0; i<animalArray.length; i++){
          if(animalArray[i] instanceof Dog_61){ //Dog_61クラスか判定
              Dog_61 dog = (Dog_61)animalArray[i]; //ダウンキャスト
              dog.printBow();
          }
      }
      System.out.println("-- cat --");
      for(int i=0; i<animalArray.length; i++){
          if(animalArray[i] instanceof Cat_61){ //Cat_61クラスか判定
              Cat_61 cat = (Cat_61)animalArray[i]; //ダウンキャスト
              cat.printKoban();
          }
      }
  }
}

萌えJava超入門 萌えJava超入門
またしても
Driver_63の結果と
同じっすね!
コマンドライン
>cd ws
ws>javac -encoding UTF-8 Driver_73.java
ws>java Driver_73
-- animal --
ゴン太くんだぞ! ガオー!           printName
ふなっしーだぞ! ガオー!           printName
アニマル浜口だぞ! ガオー!         printName
ヨーゼフだワン!                    printName
パトラッシュだワン!                printName
白いお父さんだワン!                printName
ニャースなのにゃ!                  printName
ドラえもんなのにゃ!                printName
ニャンパスなのにゃ!                printName
-- dog --
ヨーゼフは棒には当たらないワン!    printBow
パトラッシュは棒には当たらないワン!printBow
白いお父さんは棒には当たらないワン!printBow
-- cat --
ニャースは小判が欲しいのにゃ!      printKoban
ドラえもんは小判が欲しいのにゃ!    printKoban
ニャンパスは小判が欲しいのにゃ!    printKoban


萌えJava超入門 萌えJava超入門 萌えJava超入門
まあ動けばいいか。



お疲れ様でした。




© 2019 awasekagami