Menu
Coddy logo textTech

アップキャストとダウンキャスト

CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 30/87。

前のレッスンでは、親型の変数が子オブジェクトを保持できることを見ました:Animal myPet = new Dog()。この代入はアップキャスティングと呼ばれ、Dogは常にAnimalであるため、自動的に行われます。

アップキャストは継承階層を上に移動します。これは暗黙的であり、常に安全です:

Dog dog = new Dog();
Animal animal = dog;  // アップキャスト - 自動的

アップキャストすると、親クラスで定義されたメソッドにのみアクセスできるようになります。オブジェクトの実体は依然として Dog ですが、子クラス固有のメソッドは隠されて見えなくなります。

ダウンキャストは逆方向の操作で、親の参照を子の型に変換します。これは常に安全であるとは限らないため、明示的なキャストが必要です:

Animal animal = new Dog();  // アップキャスト
Dog dog = (Dog) animal;     // ダウンキャスト - 明示的なキャストが必要
dog.bark();                 // これでDogのメソッドにアクセスできるようになります

ダウンキャストは危険です。もしオブジェクトが実際にキャスト先の型ではない場合、Javaは実行時に ClassCastException をスローします:

Animal animal = new Cat();
Dog dog = (Dog) animal;  // コンパイルは可能ですが、実行時にクラッシュします!

コンパイラは宣言された型しか認識しないため、このエラーをキャッチすることはできません。実際のオブジェクト型は、プログラムの実行時にのみ判明します。次のレッスンでは、ダウンキャストを行う前にオブジェクトの型を安全にチェックする方法を学びます。

challenge icon

チャレンジ

簡単

アップキャスティングとダウンキャスティングの両方の動作を実証するメディアプレーヤーシステムを構築しましょう。メディアタイプの階層を作成し、親リファレンスと子リファレンスの間の変換を練習します。

コードは4つのファイルに分けて構成します:

  • Media.java: すべてのメディアタイプが共有するベースクラスを作成します。すべてのメディアアイテムは title フィールド(String)を持ちます。これを初期化するためのコンストラクタ、ゲッターメソッド getTitle()、そして "Playing: " + title と出力する play() メソッドを含めてください。
  • Song.java: Mediaを継承するクラスを作成します。Songには追加の artist フィールド(String)があります。親の初期化には super を使用してください。play() をオーバーライドして、"Playing song: " + title + " by " + artist と出力するようにします。また、"Artist: " + artist と出力する showArtist() メソッドを追加してください。
  • Podcast.java: Mediaを継承する別のクラスを作成します。Podcastには episode フィールド(int)があります。play() をオーバーライドして、"Playing podcast: " + title + " - Episode " + episode と出力するようにします。また、"Episode: " + episode と出力する showEpisode() メソッドを追加してください。
  • Main.java: メディアタイプを使用してアップキャスティングとダウンキャスティングを実証します。4つの入力(曲のタイトル、アーティスト名、ポッドキャストのタイトル、エピソード番号)を受け取ります。

    まず、Songを作成し、それをMediaリファレンスにアップキャストします。このリファレンスで play() を呼び出し、実行時のポリモーフィズムが機能することを確認してください。

    次に、そのMediaリファレンスをSongにダウンキャストし、子クラス固有のメソッドにアクセスするために showArtist() を呼び出します。

    その後、Podcastを作成し、それをMediaリファレンスにアップキャストします。このリファレンスで play() を呼び出します。

    最後に、そのMediaリファレンスをPodcastにダウンキャストし、showEpisode() を呼び出します。

4つの入力(曲のタイトル (String)、アーティスト名 (String)、ポッドキャストのタイトル (String)、エピソード番号 (int))を受け取ります。

出力は4行にする必要があります。2行は曲に関するもの(再生出力とアーティスト情報)、もう2行はポッドキャストに関するもの(再生出力とエピソード情報)です。アップキャスティングによって異なるメディアタイプを統一的に扱える一方で、ダウンキャスティングによってそれぞれの固有の機能にアクセスできることに注目してください!

チートシート

Javaにおいて、アップキャストは継承階層を上に移動し、自動的に行われます。子オブジェクトは親型の変数に代入できます:

Dog dog = new Dog();
Animal animal = dog;  // アップキャスト - 自動的

アップキャストすると、オブジェクトの実際の中身は依然として子型であっても、親クラスで定義されたメソッドにしかアクセスできなくなります。

ダウンキャストは、親の参照を子型に戻します。これには明示的なキャストが必要です:

Animal animal = new Dog();  // アップキャスト
Dog dog = (Dog) animal;     // ダウンキャスト - 明示的なキャストが必要
dog.bark();                 // これでDogのメソッドにアクセスできるようになります

ダウンキャストは危険です。オブジェクトが実際にキャスト先の型ではない場合、Javaは実行時にClassCastExceptionをスローします:

Animal animal = new Cat();
Dog dog = (Dog) animal;  // コンパイルは通りますが、実行時にクラッシュします!

コンパイラは宣言された型しか見ていないため、このエラーをキャッチできません。実際のオブジェクト型は、プログラムの実行時にのみ判明します。

自分で試してみよう

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 入力を読み込む
        String songTitle = scanner.nextLine();
        String artistName = scanner.nextLine();
        String podcastTitle = scanner.nextLine();
        int episodeNumber = scanner.nextInt();
        
        // TODO: Songを作成し、Mediaリファレンスにアップキャストする
        
        // TODO: Mediaリファレンスでplay()を呼び出す(ポリモーフィズムのデモンストレーション)
        
        // TODO: MediaリファレンスをSongにダウンキャストする
        
        // TODO: SongリファレンスでshowArtist()を呼び出す
        
        // TODO: Podcastを作成し、Mediaリファレンスにアップキャストする
        
        // TODO: Mediaリファレンスでplay()を呼び出す
        
        // TODO: MediaリファレンスをPodcastにダウンキャストする
        
        // TODO: PodcastリファレンスでshowEpisode()を呼び出す
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン