【Java】this と super 復習（エラー・コーディング規則）

# this と super の復習


## this と super の使い方を知る
基本的には [this] と [super] を使用する際の軸となる考え方は一緒で、主に下記のような場合に使用します。


自[クラス]の [インスタンス] の [フィールド変数] ／ [メソッド] の前に付与して

- **自 または 親 [クラス] の [フィールド] や、メソッド( [コンストラクタ]含 )を優先的に参照する場合**
- **自 または 親 [クラス] の [フィールド] や、メソッド( [コンストラクタ]含 ) の [引数] や、[メソッド] 内で 一時的に使用するローカル変数を区別する場合**

## this と super の挙動
こちらのコードをもとに、見ていきます。

【GroupWorker.java】

```java
package practiceThisAndSuper;

//「団員」という概念のクラス
public class GroupWorker {
    /** empId: 団員番号 */
    private int groupId;

    /** name: 氏名 */
    private String name;

    /** コンストラクタ: 引数なし */
    public GroupWorker() {
    }

    public GroupWorker(int groupId, String name) {
        this.groupId = groupId;
        this.name = name;
    }

    // ... フィールド変数のゲッターとセッター（※省きます）

    // Getter Setter -------------------------------

    // Getter
    public int getGroupId() {
        return this.groupId;
    }

    // Setter
    public void setGroupId(int groupId) {
        this.groupId = groupId;
    }

    // Getter
    public String getName() {
        return this.name;
    }

    // Setter
    public void setName(String name) {
        this.name = name;
    }

    // Getter Setter -------------------------------
    /**
     * 団員情報をコンソールへ出力するメソッド
     */
    public void printGroupWorker() {
        System.out.println("団員番号: " + this.groupId);
        System.out.println("氏名　　: " + this.name);
    }
}


```
【RocketGroupWorker.java】

```java
package practiceThisAndSuper;

//ロケット団員クラス
class RocketGroupWorker extends GroupWorker {
    /** isExecutive: 幹部フラグ（幹部であるかどうかを true/false で判断するためのフィールド変数） */
    boolean isExecutive;

    public RocketGroupWorker() {
    }

    /**
     * コンストラクタ: 引数あり
     *
     * @param groupId
     * @param name
     */
    public RocketGroupWorker(int groupId, String name) {
        // ①挙動確認: 親クラス（GroupWorker）のコンストラクタを呼び出す
        super(groupId, name);

        // ③挙動確認: thisを指定せずに格納する その1
        boolean isExecutive;
        if (groupId != 10) {
            isExecutive = true;
        } else {
            isExecutive = false;
        }
        System.out.println(this.isExecutive ? "幹部です" : "幹部ではない");
    }

    /**
     * コンストラクタ: 引数あり
     *
     * @param groupId
     * @param name
     * @param isExecutive
     */
    public RocketGroupWorker(int groupId, String name, boolean isExecutive) {

        // ①挙動確認: 親クラス（GroupWorker）のコンストラクタを呼び出す
        super(groupId, name);

        // ②挙動確認: 自クラスのフィールド変数（isExecutive）へコンストラクタの引数を格納する
        this.isExecutive = isExecutive;

        // ③挙動確認: thisを指定せずに格納する その2
        isExecutive = true;
        System.out.println(this.isExecutive ? "幹部です" : "幹部ではない");

        // ④挙動確認: thisとsuperで同じメソッドを呼び出す
        this.printGroupWorker();
        super.printGroupWorker();
    }

    // ... フィールド変数のゲッターとセッター（※省きます）
    // Getter
    public boolean getIsExecutive() {
        return this.isExecutive;
    }

    // Setter
    public void setIsExecutive(boolean isExecutive) {
        this.isExecutive = isExecutive;
    }
}

```
### ①挙動確認: 親クラス（GroupWorker）のコンストラクタを呼び出す

```java
//①挙動確認: 親クラス（GroupWorker）のコンストラクタを呼び出す
super(groupId, name);
```
> ポピュラーの使用方法で、**「特に異なる 初期化処理 などを行う必要がない場合」**はこれ。


[super] の実体は、「GroupWorker.java（親[クラス]）」
「RocketGroupWorker.java」 の [コンストラクタ]（二箇所）で呼び出していますが、
[継承]先で [オーバーライド] せずに親[クラス]の [コンストラクタ] を利用しています。

### ②挙動確認: 自クラスのフィールド変数（isExecutive）へコンストラクタの引数を格納する

```java
// ②挙動確認: 自クラスのフィールド変数（isExecutive）へコンストラクタの引数を格納する
this.isExecutive = isExecutive;
```
> **[this] の基本の使い方**は<font color="Blue">**「ローカル変数とフィールド変数を明確に区別するため」。**</font>

例では、[フィールド] 変数の isExecutive と 引数の isExecutive を明確に区別した使用法で、[this] を付与して正しい値の受け渡しを行えています。


### ③挙動確認: thisを指定せずに格納する

> **自クラスの [フィールド変数] なのか、ローカル変数／[引数]なのかが分かりづらい**

[this] を付与していないことが原因で ローカル変数／引数の値を変更してしまっています。

この場合、起こりうる結果としては以下になります。

> 【その１の場合】
フィールド変数へ値を格納することを意図していたとしても、実際に値が格納されるのはローカル変数

```java
        // ③挙動確認: thisを指定せずに格納する その1
        boolean isExecutive;
        if (groupId != 10) {
            isExecutive = true;
        } else {
            isExecutive = false;
        }
        System.out.println(this.isExecutive ? "幹部です" : "幹部ではない");
```

【その2の場合】

- フィールド変数へ値を格納することを意図していたとしても、実際に値が格納されるのは引数
- 仮に②と③の処理順が逆であった場合でも、実際に値が格納されるのは引数になる

```java
// ③挙動確認: thisを指定せずに格納する その1
        boolean isExecutive;
        if (groupId <= 10) {
            isExecutive = true;
        } else {
            isExecutive = false;
        }
        System.out.println(this.isExecutive ? "幹部です" : "幹部ではない");
				 .....
				 .....
				 .....
				 .....
				 
// ③挙動確認: thisを指定せずに格納する その2
        isExecutive = true;
        System.out.println(this.isExecutive ? "幹部です" : "幹部ではない");
```

何故かというとコンパイル時には以下のような「**優先順位が存在するから**」です。

> <font color="Purple">**「ローカル変数／メソッドの引数」 ＞ 「フィールド変数」**</font>

ローカル変数と [メソッド] の [引数] が同名の場合 は、コンパイル時に  <font color="Orange">ワーニング</font>が 表示されます ので即時対応が可能なのですが、
 [フィールド変数] とローカル変数（or [メソッド]の[引数]）の場合 は、 <font color="Orange">ワーニング</font>は 表示されません。

```java
// mainメソッドで 定義
RocketGroupWorker be = new RocketGroupWorker(1000, "ムサシ");


// ③挙動確認: thisを指定せずに格納する その1
        boolean isExecutive;
        if (groupId != 10) {
            isExecutive = true;
        } else {
            isExecutive = false;
        }
        System.out.println(this.isExecutive ? "幹部です" : "幹部ではない");
```
出力結果

```
幹部ではない
```
**boolean 型の値に関しては、初期値が false となってます。**

そのため、この場合は [フィールド変数]（ isExecutive  ）の値と、 条件分岐後の格納値は一致しているため、
初期化時に期待する結果（フィールド変数の isExecutive  が false であること）は変わりません。


`isExecutive be = new isExecutive(1, "サカキ"); `のように [コンストラクタ] を呼び出した場合は、
条件分岐の結果true が格納されてしまいますので、[フィールド変数]（ isExecutive ）は意図した初期化ができません。

上記はフィールド変数に値を格納したいはずなので、

- [this] を付与をする
- 同名のローカル変数は避ける

といったことをやるべきです。

### 「一時的に同名のローカル変数」を用意したい場合

2パターン挙げます

#### 1. **頭文字に「一時的な」という意味の「Temporary」を使用する**

```java
boolean tmpIsExecutive;
        if (groupId != 10) {
            tmpIsExecutive = true;
        } else {
            isExecutive = false;
        }
this.isExecutive = tmpIsExecutive;

```
#### 2. 一番スッキリ書く方法

一番ベストの書き方はこちら
こちらの書き方がベストですが、最初のうちは 1の `if と else`のブロックの考え方を意識すること。

```java
// (groupId != 10)の結果値である true/false が戻り値として格納される
this.isExecutive  = (groupId != 10);
```

実行結果

```java
...
isExecutive = true;
System.out.println(this.isExecutive ? "幹部です" : "幹部ではない");
```

出力結果

```
幹部ではない
```
この処理において `isExecutive = true;` が、
this.isExecutive = true; を意図してコーディングしたものである場合は話が変わってきます。

### ④挙動確認: thisとsuperで同じメソッドを呼び出す

こちらの

- this.printGroupWorker();
- super.printGroupWorker();

両方共、親 [クラス] である GroupWorker の printGroupWorker() を呼び出しています。
言い方を変えれば[オーバーライド]することにより、上記の [this] と [super] の呼び出し先は変わるということ。

```java
        // ④挙動確認: thisとsuperで同じメソッドを呼び出す
        this.printGroupWorker();
        super.printGroupWorker();
```
#### RocketGroupWorker [クラス]で printGroupWorker() をオーバーライドする

```java
/**
 * 団員情報をコンソールへ出力するメソッド（幹部フラグを含む）
 */
public void printGroupWorker() {
    super.printGroupWorker();
    System.out.println("幹部フラグ: " + this.isExecutive);
}
```
上記のように[オーバーライド]した場合、 **「[this] は自[クラス]で[オーバーライド]した printGroupWorker() を参照する。」＊＊

#### 命名規則に関して重要なポイント

**「値を受け渡す元と先の 変数に関して、意味的にも値として同じ場合、同様の命名規則」にしてください。**

実装時はそのクラスの内容に適した 変数名・メソッドや[メソッド]名を実装していく訳ですが、要するに「疑問を招くような命名をするな」ということ。

`例:「 name 」という変数に「 namae 」という[引数]が格納される`

ですが、以下のように変数名と[引数]名がことなっていても、「同じ値がはいっていますよ」と明示したような[引数]名なら許容度です。

```java
// parm は parameter(パラメーター)の意味
this.age = parmAge;
this.name = parmName;
```

ただ結論、**「[this] を付与する方向でコーディングしたほうが良い」**です。

[this]をつけることによって、コード量が大量になって、似たような命名の変数やメソッドを使用するなった場合であっても、目当てのコードが探しやすくなります。

##　thisやsuperが許容されないケース

### 【ケース1】[コンストラクタ]の前に処理が存在する

**コンストラクタ内の処理として [this] や [super] を使用する場合は、<font color="Red">処理の一番時最初に記述しなければなりません。</font>**

```java
    public BlueEmployee(int empId, String name) {
        boolean isExecutive = (groupId == 1);
				this(groupId, name); // ここでエラー
        super(groupId, name); // ここでエラー
```

この場合、以下のようなエラーが表示されます。

> コンストラクター呼び出しは、コンストラクター内の最初のステートメントである必要があります。

このような場合はエラーが吐かれて実行は不可ですので、上記のようなエラーの時はチェックしてみましょう。

### 【ケース2】static修飾子ついている

<font color="Red">static修飾子 が付与されたもの(クラス,変数、定数、メソッド) には[this] と [super] は付与することができません</font>

#### サンプルコード

問題ないコードはこちら

```java
public class StaticError {

    public static void main(String[] args) {
        StaticError.callPrintln(); // OK
    }

    private static void callPrintln() {
        System.out.println("解消方法1: 先頭にクラス名を付与する");
        System.out.println("解消方法2: メソッドの定義時にstaticを追加");
    }
}
```
実行結果

```
解消方法1: 先頭にクラス名を付与する
解消方法2: メソッドの定義時にstaticを追加
```
こちらはエラーになるコードです

```java
public class StaticError {

    public static void main(String[] args) {
        this.callPrintln(); // staticメソッド内のためエラーになる
    }

    private static void callPrintln() {
        System.out.println("解消方法1: 先頭にクラス名を付与する");
        System.out.println("解消方法2: メソッドの定義時にstaticを追加");
    }
}
```
実行結果

```
Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	static コンテキストでは this を使用できません

	at practiceThisAndSuper.StaticError.main(StaticError.java:6)
```
コード内に解消方法なども書きましたが、
> static コンテキストでは this を使用できません

こちらのエラー（ワーニング）が出た際の解消方法は2つあります。

- **先頭に[クラス]名を付与**
- **[メソッド]の定義時に static を追加**

つまりは、**staticとなった[クラス]、変数、定数、[メソッド]は [this] ではなく、自[クラス]名を明記しましょう**

[インスタンス]:https://qiita.com/takahirocook/items/ec01cdcbb440cf0d1cc4
[インスタンス化]:https://qiita.com/takahirocook/items/ec01cdcbb440cf0d1cc4
[アクセス修飾子]:https://qiita.com/takahirocook/items/e51b0b9d37d95ad587fe
[フィールド]:https://qiita.com/takahirocook/items/28df75a133049a74ece1
[フィールド変数]:https://qiita.com/takahirocook/items/28df75a133049a74ece1
[new演算子]:https://qiita.com/takahirocook/items/00f9f97592bf50831d39
[カプセル化]:https://qiita.com/takahirocook/items/e469a7c0539a0012868e
[クラス]:https://qiita.com/takahirocook/items/50cbbdca8e21539170e9
[メソッド]:https://qiita.com/takahirocook/items/5bfe43576d87a2a4006c
[mainメソッド]:https://qiita.com/takahirocook/items/f4635915337303de338c
[メソッドの呼び出し]:https://qiita.com/takahirocook/items/f4635915337303de338c
[コンストラクタ]:https://qiita.com/takahirocook/items/fa1822f2f22c3786593e
[引数]:https://qiita.com/takahirocook/items/5e5b0ba79e869f4a592e
[戻り値]:https://qiita.com/takahirocook/items/3b6fa670a1d6dd4a9386
[this]:https://qiita.com/takahirocook/items/d251ec4693c68f6b9538
[getter・setter]:https://qiita.com/takahirocook/items/27828bc8477735612021
[setter]:https://qiita.com/takahirocook/items/27828bc8477735612021
[getter]:https://qiita.com/takahirocook/items/27828bc8477735612021
[オブジェクト指向]:https://qiita.com/takahirocook/items/041ba7a096b71ab8ffd4
[継承]:https://qiita.com/takahirocook/items/6c84ea66a6e2ad536a37
[オーバーライド]:https://qiita.com/takahirocook/items/09dd8e5f56d6617ce45a
[オーバーロード]:https://qiita.com/takahirocook/items/b937c3c07126fe7e02a4
[this]:https://qiita.com/takahirocook/items/d251ec4693c68f6b9538
[super]:https://qiita.com/takahirocook/items/75a07131e7e791c8442c