【わかりやすく解説‼】Javaのポリモーフィズムの使い方

## 1.事前知識
- [【最新】UbuntuでJavaの環境を構築する方法](https://qiita.com/ryome/items/37c53e9638a9c6ea146a)

- [【初心者でもできる‼】Windows10にJava環境を作る方法（JDK14.0.1）](https://qiita.com/ryome/items/30135570954e36196821)

- [【わかりやすく解説‼】Javaのインスタンスの使い方](https://qiita.com/ryome/items/62ba0d8395af6698053a)

- [【初心者でもできる‼】Windows10にEclipseをインストールする方法（Java環境構築）](https://qiita.com/ryome/items/b47c5acdaa52cffbec58)

- [【わかりやすく解説‼】Javaのカプセル化の使い方](https://qiita.com/ryome/items/fc44dfad297b35bf7559)

- [【わかりやすく解説‼】Javaの継承の使い方【オーバーライドの解説あり】](https://qiita.com/ryome/items/97b82c5519e39d3f21c1)

- [【わかりやすく解説‼】Javaにおける参照型の型変換](https://qiita.com/ryome/items/2453949b978bf166e204)

事前知識として、上記リンクの内容が必要です。


## 2.ポリモーフィズムとは

- `ポリモーフィズム` とは、 `異なる処理` を持つオブジェクトを、 `同一の操作` で扱うことができることを指す。
- `操作している側` は、オブジェクトの `処理の違いを意識せず` に操作を利用できる。
- `ポリモーフィズム` は、 `多様性` ・ `多態性` ・ `多相性` ともいう。
- `ポリモーフィズム` は、 `抽象クラス` を継承したサブクラスのインスタンスを `抽象クラスの型` で扱うことで実現している。


## 3.抽象クラスとは

- `抽象クラス` とは、 `継承されることを前提` に作られたクラスである。
- `抽象クラス` は、 `インスタンス化できない` 特徴を持っている。
- `抽象クラス` には、`オーバーライド` されることを前提とした「`抽象メソッド`」が定義できる。
- `抽象クラス` 、 `抽象メソッド` には、「`abstract修飾子`」をつけて定義する。
- `抽象メソッド` には、 `private` / `static` / `final` 修飾子を付けることはできない。
- `抽象クラス` を利用するときは `抽象クラス` を継承した `サブクラス` を定義し、 `抽象メソッド` を `オーバーライド` する。
- `抽象クラス` を継承したクラスを `具象クラス` という。

## 4.ポリモーフィズムの基本的な書き方

```PHP:テストクラス
package パッケージ名;
public class メインクラス名{
    public static void main(String[] args) {
        // インスタンスの生成
        サブクラス名 変数名 = new サブクラス名();
        // 処理の実行
        変数名.抽象メソッド名(実引数)
    }
}
```

```PHP:抽象クラス
package パッケージ名;
abstract class 抽象クラス名{
    // インスタンス変数の定義
    private 型名 変数名;

    // コンストラクタ（インスタンス生成時に実行される）
    抽象クラス名(型名 引数){
        初期化処理など
    }
    // 抽象メソッド
    abstract 抽象メソッド名(型名 引数);
}
```

```PHP:サブクラス
package パッケージ名;
class サブクラス名 extends 抽象クラス名{
    // インスタンス変数の定義
    private 型名 変数名;

    // コンストラクタ（インスタンス生成時に実行される）
    サブクラス名(型名 引数){
        super(引数);
        初期化処理など
    }
    // オーバーライド(抽象メソッド)
    @Override
    抽象メソッド名(型名 引数){
        //処理
    }
}
```

- 基本的な `ポリモーフィズム` は上記のように記述します。

## 5.事前準備
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/866ce029-9f28-05d3-ab0b-5e7b0467aafa.png)
1. Eclipseを起動し、 `[ファイル(F)]→[新規(N)]→[Java プロジェクト]` を選択する。
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/f1c5cc3c-449f-a66a-caef-d5f681054041.png)
2. プロジェクト名に `Test1` と入力し、 `完了` ボタンをクリックする。
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/a98626bb-291e-6aa8-5d69-df243d1673ca.png)
3. `[ファイル(F)]→[新規(N)]→[クラス]` を選択する。　　　
![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/d0382456-4dd1-7474-4fbf-79735739b62c.png)
4. パッケージと名前に `Test1` と入力し、 `完了` ボタンをクリックする。
![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/deff58a6-dfe5-ec36-8a1c-e0d7d7c9833b.png)
5. `Test1.java` が作成されたことを確認する。
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/d39945ee-92f7-ab3c-3973-7d1a6b6b2de9.png)
6. 3と同様の手順でパッケージに `Test1` 、名前に `Greeting` と入力し、 `abstract` にチェックを入れ、 `完了` ボタンをクリックする。
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/1ad39e0b-5d11-d4dc-9bb6-f641b6fd3763.png)
8. 3と同様の手順でパッケージに `Test1` 、名前に `GoodMorning` 、スーパークラスに `Test1.Greeting` と入力し、 `完了` ボタンをクリックする。
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/9a281438-d32b-e696-feef-005528b0db34.png)
9. 3と同様の手順でパッケージに `Test1` 、名前に `Hello` 、スーパークラスに `Test1.Greeting` と入力し、 `完了` ボタンをクリックする。
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/e336150c-0447-e10d-61e2-df7ef1362729.png)
10. 3と同様の手順でパッケージに `Test1` 、名前に `GoodEvening` 、スーパークラスに `Test1.Greeting` と入力し、 `完了` ボタンをクリックする。
![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/3e70e2c0-07c3-f1f1-d9ce-717b52bafd37.png)
11. `Test1.java` 、 `Greeting.java` 、 `GoodMorning.java` 、 `Hello.java` 、 `GoodEvening.java` が作成されれば成功。

## 6.記述例

```java:Test1.java
package Test1;
public class Test1 {
    public static void main(String[] args) {
        // インスタンスの生成
    	Greeting[] greeting = {new GoodMorning("A"),new GoodMorning("B"),new GoodMorning("C")};

    	// 挨拶表示
    	for(int i = 0;i < greeting.length;i++) {
    		greeting[i].showGreeting();
    	}
    }
}
```

```java:Greeting.java
package Test1;
public abstract class Greeting {
	// インスタンス変数
	private String name;

	// コンストラクタ
	public Greeting(String name) {
		this.name = name;
	}
	// getter
	public String getName() {
		return name;
	}
	// 挨拶の表示
	abstract void showGreeting();
}
```

```java:GoodMorning.java
package Test1;
public class GoodMorning extends Greeting {
	// コンストラクタ
	public GoodMorning(String name) {
		super(name);
	}
	// 挨拶の表示
	@Override
	void showGreeting() {
		System.out.println(getName()+"さん、おはようございます。");
	}
}
```

- 上記の文をコピーして、文字コードは `S-JIS` を指定し、ファイル名を `Test1.java` , `Greeting.java` , `GoodMorning.java` で保存し、実行するとこうなります。↓↓　　　　　　　　　　　　　　　　　　　　　　　　　　
![07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/cc6d8c78-ce92-3e20-7b9f-cd299a13c5da.png)


## 7.ポリモーフィズムをする理由
- `オブジェクト指向` では、 `あらゆる事象` を `オブジェクト` として捉える。
- そのため、 `オブジェクトの数` に比例して `インスタンス化するクラスの数` も増加する。
- `オブジェクトの数だけコードを書く` と考えると途方もない数字となり書き切ることは難しい。
- `ポリモーフィズム` は、オブジェクト同士の共通点を見つけ、抽象化することで `コードの簡略化` と `コードの書く量を減らしている` 。

### A,B,Cの3人がそれぞれ挨拶をするシステム
- A,B,Cが順番に挨拶をする。
- 挨拶は「`おはようございます`」,「`こんにちは`」,「`こんばんは`」の3種類。
- 上記のようなシステムを作る際に `ポリモーフィズム` をしなかった場合、下記のコードようにコード量が増えて複雑化してしまう。

```java:Test1.java
package Test1;
public class Test1 {
    public static void main(String[] args) {
        // インスタンスの生成
    	GoodMorning[] goodmorning = {new GoodMorning("A"),new GoodMorning("B"),new GoodMorning("C")};
    	Hello[] hello = {new Hello("A"),new Hello("B"),new Hello("C")};
    	GoodEvening[] goodevening = {new GoodEvening("A"),new GoodEvening("B"),new GoodEvening("C")};

    	// 挨拶表示
    	for(int i = 0;i < goodmorning.length;i++) {
    		goodmorning[i].showGreeting();
    	}
    	for(int i = 0;i < hello.length;i++) {
    		hello[i].showGreeting();
    	}
    	for(int i = 0;i < goodevening.length;i++) {
    		goodevening[i].showGreeting();
    	}
    }
}
```

```java:Hello.java
package Test1;
public class Hello {
	// インスタンス変数
	String name;

	// コンストラクタ
	public Hello(String name) {
		this.name = name;
	}
	// 挨拶の表示
	void showGreeting() {
		System.out.println(name+"さん、こんにちは。");
	}
}
```

```java:GoodMorning.java
package Test1;
public class GoodMorning{
	// インスタンス変数
	String name;

	// コンストラクタ
	public GoodMorning(String name) {
		this.name = name;
	}
	// 挨拶の表示
	void showGreeting() {
		System.out.println(name+"さん、おはようございます。");
	}
}
```

```java:GoodEvening.java
package Test1;
public class GoodEvening {
	// インスタンス変数
	String name;

	// コンストラクタ
	public GoodEvening(String name) {
		this.name = name;
	}
	// 挨拶の表示
	void showGreeting() {
		System.out.println(name+"さん、こんばんは。");
	}
}
```

- 上記の文をコピーして、文字コードは `S-JIS` を指定し、ファイル名を `Test1.java` , `GoodMorning.java` , `Hello.java` , `GoodEvening.java` で保存し、実行するとこうなります。↓↓　　　　　　　　　　　　　　　　　　　　　　　　　　
![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/8d7b40bf-364b-7d92-c117-964aa9fe7e93.png)

- 上記の例では、 `ポリモーフィズムを使用していない` ため、 `配列が3つ` 存在し、それに対応した `for文` が存在する。
- `ポリモーフィズム` を使用して `抽象化` することで `配列を1つ` にまとめることができる。
- 上記の例の `GoodMorning.java` , `Hello.java` , `GoodEvening.java` を `抽象化` すると以下のようになる。


```java:Test1.java
package Test1;
public class Test1 {
    public static void main(String[] args) {
        // インスタンスの生成
    	Greeting[] greeting = {
    			new GoodMorning("A"),new GoodMorning("B"),new GoodMorning("C"),
    			new Hello("A"),new Hello("B"),new Hello("C"),
    			new GoodEvening("A"),new GoodEvening("B"),new GoodEvening("C")
    			};

    	// 挨拶表示
    	for(int i = 0;i < greeting.length;i++) {
    		greeting[i].showGreeting();
    	}
    }
}
```

```java:Greeting.java
package Test1;
public abstract class Greeting {
	// インスタンス変数
	private String name;

	// コンストラクタ
	public Greeting(String name) {
		this.name = name;
	}
	// getter
	public String getName() {
		return name;
	}
	// 挨拶の表示
	abstract void showGreeting();
}
```

```java:Hello.java
package Test1;
public class Hello extends Greeting{
	// コンストラクタ
	public Hello(String name) {
		super(name);
	}
	// 挨拶の表示
	@Override
	void showGreeting() {
		System.out.println(getName()+"さん、こんにちは。");
	}
}
```

```java:GoodMorning.java
package Test1;
public class GoodMorning extends Greeting {
	// コンストラクタ
	public GoodMorning(String name) {
		super(name);
	}
	// 挨拶の表示
	@Override
	void showGreeting() {
		System.out.println(getName()+"さん、おはようございます。");
	}
}
```

```java:GoodEvening.java
package Test1;
public class GoodEvening extends Greeting {
	// コンストラクタ
	public GoodEvening(String name) {
		super(name);
	}
	// 挨拶の表示
	@Override
	void showGreeting() {
		System.out.println(getName()+"さん、こんばんは。");
	}
}
```
- 上記の文をコピーして、文字コードは `S-JIS` を指定し、ファイル名を `Test1.java` , `Greeting.java` , `GoodMorning.java` , `Hello.java` , `GoodEvening.java` で保存し、実行するとこうなります。↓↓　　　　　　　　　　　　　　　　　　　　　　　　　　
![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/8d7b40bf-364b-7d92-c117-964aa9fe7e93.png)

## 7.GitHub
GitHubにソースコードを公開しています。

https://github.com/ryomeblog/qiita/tree/master/%E3%80%90%E3%82%8F%E3%81%8B%E3%82%8A%E3%82%84%E3%81%99%E3%81%8F%E8%A7%A3%E8%AA%AC%E2%80%BC%E3%80%91Java%E3%81%AE%E3%83%9D%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%95%E3%82%A3%E3%82%BA%E3%83%A0%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9


## 8.関連
- [【覚えておくと便利!!!】Eclipseにおけるコンストラクタとgetter/setterの簡易作成](https://qiita.com/ryome/items/6c487ccc0c39847cd55f)
- [【覚えておくと便利!!!】Eclipseにおける継承クラスの簡易作成](https://qiita.com/ryome/items/4fcf62b4bc60fb6a4d07)
- [【初心者でもできる‼】Javadocの書き方](https://qiita.com/ryome/items/4f2d5928c8aaf195f407)
- [【わかりやすく解説‼】Javaのオーバーロードの使い方](https://qiita.com/ryome/items/f1ca8cc7538f4c6d26c0)