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

サブクラスクラス

スーパークラスのメソッド実行
super. を使うと、スーパークラスのメソッドやプロパティにアクセスできます。
super.メソッド();
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オブジェクトの Array型として操作できます。
Character[]
Wizard、Warriorのインスタンスを、Character[] の配列で初期化します。
App.java
Wizard wizard1 = new Wizard("アリス");
Wizard wizard2 = new Wizard("テリー");
Warrior warrior1 = new Warrior("ボブ");
// Array型に Characterのオブジェクトで初期化
Character[] characters = { wizard1, wizard2, warrior1 };
System.out.println(characters);
コンソールで確認すると、Characterクラスとして追加されています。
結果
[Lcharacter.Character;@xxxxx
ポリモーフィズムで処理
foreach で処理
Character[] データを、foreachで繰り返し表示してみましょう。
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();
// foreach
for (Character character : characters) {
System.out.println(character.name + "の攻撃");
character.attack(monster1);
System.out.println(monster1.isAlive());
}
}
動作確認
Wizardは自分のクラスのattack() 、Warriorはオーバーライドしたattack() が実行されます。
結果
--- Battle ---
アリスの攻撃
true
テリーの攻撃
true
ボブの攻撃
オーバーライド
false
演習
問題1
ポリモーフィズムの説明として正しいのはどれですか?
- 同じメソッド名でも、異なる動作を実行
- 共通のメソッドやプロパティを1つのクラスにまとめ、引き継ぐ
- オブジェクトを隠蔽して、外部からデータ操作を拒否してデータの不整合を防ぐ
- 抽象メソッドと呼ばれ、メソッドの仕様のみを定義したもの
問題2
クラスに「@Override」のように、「@」でコーディングする記法をなんといいますか?
- パッケージ
- アノテーション
- スーパークラス
- サブクラス
問題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("集団行動");
}
}