※当サイトの記事には、広告・プロモーションが含まれます。

Java ポリモフィズム(多態性とか多様性とも呼ばれるらしい)

ポリモフィズムを実現するには、抽象クラスかインターフェイスを使うのが一般的なようです。オーバライドも必要みたいです。

ポリモフィズムとは?

そもそも、ポリモフィズムって何なの?って話ですが、

ポリモーフィズム」とは、「抽象クラス」や「インターフェース」などを利用してメソッドの呼び出し方法を共通化し、さらに「オーバーライド」させることで同じメソッドを呼び出しても、実際のインスタンス毎にその挙動を変化させようとするものです。 

オブジェクト指向 - Java入門 - IT専科

というような説明がなされています。 

ポリモフィズムを使わない場合

Javaでは、データ型がしっかりしているため、キャスト(静的キャスト、アップキャストやダウンキャスト)しない限り普通は、異なるデータ型の代入はできないようになっています。 

例えば、下記のような4つのクラスを作成した場合、

f:id:ts0818:20170708120748p:plain

public class Hero {
  private int hp;
  private String name;
  
  public Hero(String name, int hp) {
    this.name = name;
    this.hp = hp;
  }
  
  public void attack() {
    System.out.println("勇者の一撃!");
  }
}
public class Masician {
  private int hp;
  private String name;
  
  public Masician(String name, int hp) {
    this.name = name;
    this.hp = hp;
  }
  
  public void attack() {
    System.out.println("魔法使いの一撃!");
  }
}
public class Warrior {
  private int hp;
  private String name;
  
  public Warrior(String name, int hp) {
    this.name = name;
    this.hp = hp;
  }
  
  public void attack() {
    System.out.println("戦士の一撃!");
  }
}
public class Monk {
  private int hp;
  private String name;
  
  public Monk(String name, int hp) {
    this.name = name;
    this.hp = hp;
  }
  
  public void attack() {
    System.out.println("武闘家の一撃!");
  }
}
public class Main {
  public static void main(String[] args) {
  
    // それぞれのインスタンスを生成
    Hero h = new Hero("佐藤", 100);
    Masician m = new Masician("鈴木", 100);
    Warrior w = new Warrior("高橋", 100);
    Monk m = new Monk("田中", 100);
    
    // それぞれのattack()メソッドを実行
    h.attack();
    m.attack();
    w.attack();
    m.attack();
    
  }

}

同じattack()メソッドでも、それぞれのクラスによって処理内容が異なるため、個別に呼び出す必要があります。

ポリモフィズムを使う場合

Characterという抽象クラスを継承する場合、

f:id:ts0818:20170708125331p:plain

public abstract class Character {

  private String name;
  private int hp;
  
  public Character(String name, int hp) {
    this.name = name;
    this.hp = hp;
  }
  
  public void attack();
  
}
public class Hero extends Character {

  public Hero(String name, int hp) {
    super(name, hp);
  }

  @Override  
  public void attack() {
    System.out.println("勇者の一撃!");
  }
}
public class Masician extends Character {

  public Masician(String name, int hp) {
    super(name, hp);
  }

  @Override  
  public void attack() {
    System.out.println("魔法使いの一撃!");
  }
}
public class Warrior extends Character {

  public Warrior(String name, int hp) {
    super(name, hp);
  }

  @Override  
  public void attack() {
    System.out.println("戦士の一撃!");
  }
}
public class Monk extends Character {

  public Monk(String name, int hp) {
    super(name, hp);
  }
  
  @Override
  public void attack() {
    System.out.println("武闘家の一撃!");
  }
}
public class Main {

  public static void main(String[] args) {
  
    // Characterクラス型の配列を用意
    Character[] c = new Character[4];
    // それぞれのインスタンスを生成    Character[] c = new Character[4];
    Character[0] = new Hero("佐藤", 100);
    Character[1] = new Masicain("鈴木", 100);
    Character[2] = new Hero("高橋", 100);
    Character[3] = new Masicain("田中", 100);
    
    // それぞれのattack()メソッドを実行
    for(int index = 0; index < c.length; index++) {
      Character[index].attack();
    }

  }

}

Javaでは、スーパークラスの変数にサブクラスのインスタンスを代入することができます。これを、アップキャストというようです。

アップキャストは、is a 関係 が成り立っていないとできないようです。

f:id:ts0818:20170708131609p:plain

Hero is a Character が、 成り立つような関係のことらしいです。

アップキャストすることで、Chracterクラスにそれぞれ異なるクラス型である、Hero、Masicain、Warrior、Monkといったクラスのインスタンスを代入できています。Characterクラスのattack()メソッドを経由して、それぞれのクラスのattack()メソッドが呼び出せます。

このように、外側からはCharacterクラスにしか見えないのに、Heroクラス、Masicianクラス、Warriorクラス、Monkクラスなど様々なクラスのふるまいを実行できる様が、ポリモフィズム多態性とか多様性)と呼ばれる所以でしょうか。

 

Characterという抽象クラスとBehaviorというインターフェイスを使った場合、

f:id:ts0818:20170708130043p:plain

public interface Behavior {

  public void attack();
  
}
public abstract class Character implements Behavior {

  private String name;
  private int hp;
  
  public Character(String name, int hp) {
    this.name = name;
    this.hp = hp;
  }

}
public class Hero extends Character {

  public Hero(String name, int hp) {
    super(name, hp);
  }

  @Override  
  public void attack() {
    System.out.println("勇者の一撃!");
  }
}
public class Masician extends Character {

  public Masician(String name, int hp) {
    super(name, hp);
  }

  @Override  
  public void attack() {
    System.out.println("魔法使いの一撃!");
  }
}
public class Warrior extends Character {

  public Warrior(String name, int hp) {
    super(name, hp);
  }

  @Override  
  public void attack() {
    System.out.println("戦士の一撃!");
  }
}
public class Monk extends Character {

  public Monk(String name, int hp) {
    super(name, hp);
  }
  
  @Override
  public void attack() {
    System.out.println("武闘家の一撃!");
  }
}
public class Main {

  public static void main(String[] args) {
  
    // Characterクラス型の配列を用意
    Character[] c = new Character[4];
    // それぞれのインスタンスを生成
    Character[0] = new Hero("佐藤", 100);
    Character[1] = new Masicain("鈴木", 100);
    Character[2] = new Hero("高橋", 100);
    Character[3] = new Masicain("田中", 100);
    
    // それぞれのattack()メソッドを実行
    for(int index = 0; index < c.length; index++) {
      Character[index].attack();
    }

  }

}

とも書けるようです。共通するメソッドはインターフェースに記述するのが良いようです。クラスなどの設計をしっかり考えていく必要がありそうです。

今回はこのへんで。