21.
ポリモーフィズム
ポリモーフィズムとは
オブジェクト指向の三大要素
ポリモーフィズムは多態性、多様性などと呼ばれ、オブジェクト指向の三大要素の1つです。
- 継承
- カプセル化
- ポリモーフィズム
オーバーロードとオーバーライド
オーバーロードやオーバライドはポリモーフィズムにあたり、同じメソッドでも異なる動作をするのがポリモーフィズムの大きな特徴です。
オーバーライド
オーバーライドとは
スーパークラスで定義したメソッドを、サブクラス再定義することをオーバーライド(Override) といいます。オーバーライドは、サブクラスでスーパークラスのメソッドを上書きしたり、機能追加して実行できます。
オーバーライドの条件
- 引数の型、数、順番が同じ
- 原則、戻り値の方が同じ
- アクセス修飾子がスーパークラスの公開範囲内に収まっている
アノテーション
メソッドやプロパティ定義の前に @で記述する記法をアノテーションといいます。アノテーションは、Javaで明示的な機能を宣言する記法で、Javaフレームワークでは多数のアノテーションがあります。
アノテーションの例(Java標準)
アノテーション | 説明 |
---|---|
@Override | オーバーライドの定義 |
@Deprecated | クラスやメンバーなどが非推奨 |
@SuppressWarnings | コンパイラー警告を抑制 |
@SafeVarargs | 可変長引数の型安全を宣言 |
@FunctionalInterface | 関数型インタフェースの定義 |
オーバーライドメソッドの定義
スーパークラスと同じメソッドを定義します。メソッドの前には @Overrideをつけます。
@Override
修飾子 データ型 メソッド(引数) {
//処理
}
オーバーライドのコンパイルエラー
オーバーライドは、スーパークラスと同じメソッドにしなければいけません。メソッド名、戻り値、引数が違うと、コンパイルエラーになります。
スーパークラス

サブクラスクラス

スーパークラスのメソッド実行
「super」を使うと、サブクラスからスーパークラスのメソッドを直接実行することもできます。
@Override
修飾子 データ型 メソッド(引数) {
//処理
super.メソッド();
}
オーバーライドの例
Warriorクラスで、attack() メソッドをオーバーライドしてみましょう。 Warriorの攻撃では、1/5の確率で攻撃力を倍にする仕様に変更します。
Warrior.java
@Override
public void attack(Monster monster) {
System.out.println("オーバーライド");
//元の攻撃力をキャッシュ
int attackPower = this.attackPower;
// 1/5の確率で攻撃力を倍にする
Random rand = new Random();
if (rand.nextInt(5) == 0) this.attackPower = attackPower * 2;
// スーパークラスのattack() を実行
super.attack(monster);
// 攻撃力を元に戻す
this.attackPower = attackPower;
}
結果
1/5の確率で、攻撃力が変わることを確認してみましょう。
オーバーライド
-14
false
ポリモーフィズムのメリット
継承とポリモーフィズムをうまく使うと、コードをまとめて可読性がよくなるメリットがあります。
複数のクラスを同時に扱う
「Wizard」「Warrior」クラスは異なるクラスですが、「Character」クラスを継承しているので、「Character」として扱うことができます。
Character[]にまとめる
「Wizard」「Warrior」のインスタンスを、Character[] データで初期化できます。
App.java
Wizard wizard1 = new Wizard("アリス");
Wizard wizard2 = new Wizard("テリー");
Warrior warrior1 = new Warrior("ボブ");
Character[] characters = { wizard1, wizard2, warrior1 };
System.out.println(characters);
結果
コンソールで確認すると、Characterクラスとして追加されています。
[Lcharacter.Character;@xxxxx
foreach(拡張for文)
配列(コレクション)データを繰り返す方法の1つに、**foreachと呼ばれる 拡張 for文があります。
foreach
for (データ型 一時変数 : コレクション) {
//処理
}
foreachの例
Character型の配列「characters」を繰り返し処理する場合です。
forを入力してコードアシスタントで「foreach」を選択します。
Character[]データを自動認識してfor文が入力できました。インデックスを利用しないので、通常のfor文よりもシンプルです。
for (Character character : characters) {
}
ポリモーフィズムで処理
App.java
public static void main(String[] args) {
Wizard wizard1 = new Wizard("アリス");
Wizard wizard2 = new Wizard("テリー");
Warrior warrior1 = new Warrior("ボブ");
Character[] characters = { wizard1, wizard2, warrior1 };
System.out.println(characters);
System.out.println("--- Battle ---");
Monster monster1 = new Monster();
for (Character character : characters) {
System.out.println(character.name + "の攻撃");
character.attack(monster1);
System.out.println(monster1.isAlive());
}
}
結果
「Wizard」は「Character」のattack()、「Warrior」は「Warrior」クラスでオーバーライドしたattack() が実行されています。
--- Battle ---
アリスの攻撃
true
テリーの攻撃
true
ボブの攻撃
オーバーライド
false
演習
問題1
ポリモーフィズムの説明として正しいのはどれですか?
1)同じメソッド名でも、異なる動作を実行
2)共通のメソッドやプロパティを1つのクラスにまとめ、引き継ぐ
3)オブジェクトを隠蔽して、外部からデータ操作を拒否してデータの不整合を防ぐ
4)抽象メソッドと呼ばれ、メソッドの仕様のみを定義したもの
問題2
クラスに「@Override」のように、「@」でコーディングする記法をなんといいますか?
1)パッケージ
2)アノテーション
3)スーパークラス
4)サブクラス
問題3
「Dog」「Cat」のwalk() をfor文実行してみましょう。
Animal.java
package zoo;
public class Animal {
public String type;
public String name;
public String crying;
public Animal(String name) {
super();
this.name = name;
}
public void walk() {
String message = this.name + "が歩いた";
System.out.println(message);
}
public void cry() {
System.out.println(this.crying);
}
public void escape() {
String message = this.name + "が逃げた";
System.out.println(message);
}
}
Cat.java
package zoo;
public class Cat extends Animal {
public Cat(String name) {
super(name);
this.crying = "にゃー!";
}
@Override
public void walk() {
System.out.println(this.name + "が警戒して歩いてます。");
}
public void actionSolo() {
System.out.println("単独行動");
}
}
Dog.java
package zoo;
public class Dog extends Animal {
public Dog(String name) {
super(name);
this.crying = "わん!";
}
@Override
public void walk() {
System.out.println(this.name + "が楽しそうに歩いてます。");
}
public void actionCollective() {
System.out.println("集団行動");
}
}