広告

手を動かして学ぶ Java入門 (メソッドのオーバーライド)

環境構築不要! ブラウザから直接コードを実行できます。
本記事では、クラス・メソッドのオーバーライドについて学びます。

オブジェクト指向の大事な概念である ポリモーフィズム(多態性) の基本でもあります。

15分くらいで、さくっと終わる記事をめざしています。


シリーズ一覧

続きは近日公開予定!

はじめに

この記事は paiza.IO の「Online Java compiler」を利用しています。
2024/12/17 現在、上記環境の Java バージョンは 18 です。(paiza.IO利用ガイド)

実行したコードは paiza.IO で保存および公開されることがあります。
そのため、個人情報などの機密性の高い情報は、コードとして入力しないようにご注意ください。

詳細は paiza.IO の利用規約およびプライバシーポリシーをご確認ください。

クラス継承のおさらい

コンピュータプログラミングにおける継承(けいしょう、英: inheritance)とは、任意のオブジェクトの特性を、他のオブジェクトの特性の基礎にするためのメカニズムと定義されている。

クラスの継承とは、簡単にいうと…

  • ベースとなるクラスの フィールドメソッド
  • それを 引き継いだ 新しいクラスを作る (宣言する)

ことです。

継承イメージ1

メソッドのオーバーライド

オブジェクト指向プログラミングにおいてオーバーライド (override) とは、スーパークラスで定義されたメソッドをサブクラスで定義し直し、動作を上書き(変更)することである。

オーバーライド (override) とは、本来は「優先する」や「覆す」などといった意味があります。
プログラミングにおいては「上書き」と意訳するとしっくりきます。

メソッドのオーバーライドとは、簡単にいうと…

  • スーパークラスで宣言したメソッドを、
  • サブクラスで同じメソッドとして宣言して 上書き する

ことです。

具体的な例で見てみましょう。
Shape は「図形」という意味のクラスです。

public class Shape {
    public void print() {
        System.out.println("図形の名前 : なし");
    }
}

print メソッドは、図形の名前を出力します。
Shape クラスは「具体的な図形」ではないので、名前は "なし" としています。

次に、Shape クラスを継承した Rectangle クラスを作りましょう。
Rectangle は「長方形」という意味です。

public class Rectangle extends Shape {
}

Rectangle クラスの中身は空です。
(まだメソッドのオーバーライドはしていません)

それでは、この2つのクラスを実際に動かして確認してみましょう。

Shape shape = new Shape();
shape.print();

Rectangle rectangle = new Rectangle();
rectangle.print();

Shape クラスと Rectangle クラスのインスタンスを作成して、それぞれ print メソッドを呼び出してみます。
結果がどうなるか予想してから「実行(Ctrl-Enter)」ボタンを押してください。

注意:コードは3ファイルあります。上部のタブで切り替え可能です。

タブ

(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)

いかがでしたでしょうか? 「出力」のところに

図形の名前 : なし
図形の名前 : なし

と表示されたら成功です。

ここまでは前回までの復習ですね。

次は、Rectangle クラスにメソッドを1つ宣言してみましょう。
宣言するのは、Shape クラスと同じ名前の print メソッドです。

public class Rectangle extends Shape {
    @Override
    public void print() {
        System.out.println("図形の名前 : 長方形");
    }
}

( @Override という見慣れない記述もありますが、そちらは今は気にしないでください)

それでは実際に動かして確認してみましょう。
結果がどうなるか予想してから「実行(Ctrl-Enter)」ボタンを押してください。

注意:コードは3ファイルあります。上部のタブで切り替え可能です。

タブ

(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)

いかがでしたでしょうか? 「出力」のところに

図形の名前 : なし
図形の名前 : 長方形

と表示されたら成功です。

コードの解説

最初に「オーバーライドしない例」を見てみましょう。

public class Shape {
    public void print() {
        System.out.println("図形の名前 : なし");
    }
}

public class Rectangle extends Shape {
}

この場合は、Rectangle のインスタンスの print メソッドを呼び出すと…

Rectangle rectangle = new Rectangle();
rectangle.print();
          ^^^^^^^ <--- Shape の print メソッドが呼び出される

Shape の print メソッドが呼び出されます。

結果の出力↓

図形の名前 : なし

次は「オーバーライドする例」です。

public class Shape {
    ... 省略 ...
}

public class Rectangle extends Shape {
    @Override
    public void print() {
        System.out.println("図形の名前 : 長方形");
    }
}

この場合は、Rectangle のインスタンスの print メソッドを呼び出すと…

Rectangle rectangle = new Rectangle();
rectangle.print();
          ^^^^^^^ <--- Rectangle の print メソッドが呼び出される

オーバーライドされた Rectangle の print メソッドが呼び出されます。

結果の出力↓

図形の名前 : 長方形

ここが大事なポイントです。

イメージ図1

Rectangle クラスは Shape クラスを継承しています。
そのため、通常であれば Shape クラスの print メソッドを 引き継ぎ ます。

しかし、Rectangle クラスで print メソッドを オーバーライド することで、Shape クラスの print メソッドを上書きしたわけですね。

アノテーション

Javaのアノテーションはクラスやインタフェース、メソッドやフィールド、パッケージなどに対してメタデータとして付加情報を記入する機能で、Java SE 5 で追加された。

メソッドをオーバーライドするときに記述する、アットマーク(@) を使った書き方を アノテーション といいます。

public class Rectangle extends Shape {
    @Override <--- ★この部分!
    public void print() {
        ...
    }
}

メソッドをオーバーライドするときは必ず @Override を書くようにしましょう。
書かなくてもエラーにはなりませんが、おすすめはしません。

@Override を書くことによるメリット 】

  • オーバーライドしたメソッドであることが 明確 になります。
  • メソッド名を間違えたりしてオーバーライドできないときは、コンパイルエラーで知らせてくれます。

暗黙の型変換

型変換(かたへんかん、英: type conversion)とはプログラムにおいて、あるデータ型を他のデータ型に変換することである[1]。型キャスト(英: type casting)とも呼ばれる[2]

Java では、サブクラスのインスタンスをスーパークラス型の変数に代入できます。
これを 暗黙の型変換 といいます。

イメージ図2

public class Shape {
    public void print() {
        System.out.println("図形の名前 : なし");
    }
}

public class Rectangle extends Shape {
    @Override
    public void print() {
        System.out.println("図形の名前 : 長方形");
    }
}
Shape shape = new Rectangle();
^^^^^             ^^^^^^^^^ <--- サブクラス
     <--- スーパークラス

こんな感じですね。

さて、shape 変数は Shape 型です。
その変数で print メソッドを呼び出すと、どうなるでしょうか…?

Shape shape = new Rectangle();
shape.print();

Shape クラスで宣言した print メソッドが呼び出される?
それとも、Rectangle クラスでオーバーライドした print メソッドが呼び出される?

実際に動かして確認してみましょう。
結果がどうなるか予想してから「実行(Ctrl-Enter)」ボタンを押してください。

注意:コードは3ファイルあります。上部のタブで切り替え可能です。

タブ

(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)

いかがでしたでしょうか? 「出力」のところに

図形の名前 : 長方形

と表示されたら成功です。

正解は、

  • Rectangle クラスでオーバーライドした print メソッドが呼び出される

でした。

これこそが ポリモーフィズム(多態性) の基本になります。

ノート

  • 暗黙ではなく、明示的 な型変換もあります。
    ただし、あまり使うことはないので、この記事では割愛します。(いずれ解説できたらなと…)

ポリモーフィズム(多態性)

ポリモーフィズム(英: polymorphism)とは、それぞれ異なる型に一元アクセスできる共通接点の提供[1]、またはそれぞれ異なる型の多重定義を一括表現できる共通記号の提供[2]を目的にした、型理論またはプログラミング言語理論(英語版)の概念および実装である。

Java は オブジェクト指向プログラミング 言語です。
そして、ポリモーフィズム(多態性)はオブジェクト指向の大事な概念の1つです。

ただ、オブジェクト指向にまつわるお話は難しいので、入門記事としては解説は割愛します。
Java に慣れてきたら、ぜひオブジェクト指向についても学んでみてくださいね。

応用問題

【問題】

まずは、下記のプログラムをそのまま「実行(Ctrl-Enter)」してみましょう。
結果として次のように「出力」に表示されたはずです。

図形の名前 : なし
図形の名前 : なし
図形の名前 : なし

そこで問題です。

Shape クラスを継承した、

  • Rectangle クラス
  • Circle クラス

に対して、Shape クラスの getName メソッドをオーバーライドしてください。

その結果として、プログラムを実行すると、

図形の名前 : なし
図形の名前 : 長方形
図形の名前 : 円形

と「出力」に表示されようにしてください。

それでは、Rectangle クラスと Circle クラスを修正してから「実行(Ctrl-Enter)」してみましょう。
(修正するのは Rectangle クラスと Circle クラスだけです)

注意:コードは4ファイルあります。上部のタブで切り替え可能です。

タブ

(表示がおかしいときは「コードの再読み込み」ボタンを押してみてください)

無事に、

図形の名前 : なし
図形の名前 : 長方形
図形の名前 : 円形

と出力されましたでしょうか?

もし解けなかった場合は、下記の回答例をご参照ください。

回答例

【コード】

public class Rectangle extends Shape {
    // getName メソッドをオーバーライドしてください。
    @Override
    public String getName() {
        return "長方形";
    }
}
public class Circle extends Shape {
    // getName メソッドをオーバーライドしてください。
    @Override
    public String getName() {
        return "円形";
    }
}

※ Main.java, Shape.java は書き換えません。

【出力】

図形の名前 : なし
図形の名前 : 長方形
図形の名前 : 円形

まとめ

メソッドのオーバーライドとは、

  • スーパークラスで宣言したメソッドを、
  • サブクラスで同じメソッドとして宣言して 上書き する

ことです。

オブジェクト指向の大事な概念である ポリモーフィズム(多態性) の基本でもあります。

ぜひ有効に活用していきたいですね。

次回は「手を動かして学ぶ Java入門 (メソッドのオーバーロード)」になります。


関連記事

ページの先頭へ