【Java】入れ子クラス

#入れ子クラス（Nested Class）
* **入れ子クラス**（Nested Class）
    * **staticメンバークラス**
    * **内部クラス**（Inner Class）
        * **非staticメンバークラス**
        * **匿名クラス**
   
##staticメンバークラス
* 特定クラス(MyClass)にクラス（MyHelper）が依存、MyHelperはMyClassからしか呼ばれない
* →1個の.javaファイルにまとめることを考える
* **トップレベルクラス**：ネストしてないファイル直下のクラス
* **エンクロージングクラス**：入れ子のクラスを内側に含んだクラス
    * 親クラスX：エンクロージングクラスかつトップレベルクラス
    * 子クラスY：ZのエンクロージングクラスでXの入れ子クラス
    * 孫クラスZ：Yの入れ子クラス


```java
public class MyClass{...}
class MyHelper{...}
```
* しかし、MyHelperはあくまで**パッケージプライベート**で、同じパッケージからは自由にアクセスできる
* →**staticでMyClassのプライベートにすべき！**
* エンクロージングクラスのclassブロック配下で入れ子クラス定義すると
    * **入れ子クラスはエンクロージングクラス外からは見えない**
    * 入れ子クラスの名前は**`エンクロージングクラス.入れ子クラス(MyClass.MyHelper)`**
        * エンクロージング内部ではメンバークラス名で呼び出し可能
        * `import (package名).MyClass.MyHelper;`<br>でエンクロージング外からも<br>`var h = new MyHelper();`可能

```java
//classブロック配下でMyHelper定義
public class MyClass {
  //staticメンバークラスの定義
  //メンバーはMyClass外からは見えない
  private static class MyHelper {
    public void show() {
      System.out.println("Nested class is running!");
    }
  }
  public void run() {
    //エンクロージング内部ではMyHelper呼び出し可能
    var helper = new MyHelper();
    helper.show();
  }
}
```
```java
public class NestBasic {
  public static void main(String[] args) {
    var c = new MyClass();
    c.run();
    //MyHelpeはMyClass外からは見えない
    // var h = new MyClass.MyHelper(); //エラー！
  }
}
```

##非staticメンバークラス（=内部クラス）
* static修飾子なし
* **内部クラス**：エンクロージングオブジェクトに所属
* **staticメンバークラス**：エンクロージングクラスに所属
* 内部クラスの特徴
    * 内部クラスをインスタンス化するには**エンクロージングオブジェクト必要**
    * 内部クラスからは**this変数経由でエンクロージングクラスメンバーにアクセス**
* **エンクロージングクラスのインスタンスフィールド参照用途に使用**
* 個々のインスタンスがエンクロージングオブジェクトへの参照を持つのでメモリを消費する

```java
class MyClass {
  private String str1 = "エンクロージング・インスタンス";
  private static String str2 = "エンクロージング・クラス";

  private class MyHelper {
    private String str1 = "ネスト・インスタンス";
    private static final String str2 = "ネスト・クラス";

    public void show() {
      //内部クラスはエンクロージングオブジェクトへの参照を持つ
      //MyClass.thisでアクセス可
      System.out.println(MyClass.this.str1); //エンクロージング・インスタンス
      System.out.println(MyClass.str2); //エンクロージング・クラス
    }
  }

  public void run() {
    //内部クラスのインスタンスはエンクロージングクラスのインスタンスメソッドで生成
    var helper = new MyHelper();
    helper.show();
    //エンクロージングオブジェクトから内部クラスにアクセス
    System.out.println(helper.str1); //ネスト・インスタンス
    System.out.println(MyHelper.str2); //ネスト・クラス
  }
}

```
```java
public class NestedAccess {
  public static void main(String[] args) {
    var c = new MyClass();
    c.run();
  }
}
```

##非staticメンバークラス（内部クラス）の実例
* private内部クラスを宣言したらエンクロージング外からは見えない
* 見えなくなるのは**型名のみ**、インスタンスの参照は制限なし


```java:java.util.AbstractList.java
package java.util;
import java.util.function.Consumer;
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
//...中略

    /*Iterators
    Itrクラスの内部的な実装を見せる必要はない
    外部からは実装元であるIterators型が見えたらいい
    iteratorメソッドの戻り値はIterator型
    */
    public Iterator<E> iterator() {
        return new Itr();
    }
//...中略

    /*内部クラス
    リスト内のprivateフィイールドにアクセス、配下要素を順にアクセスするイテレータを実装
    イテレータはIterator実装クラスとして別に定義する
    */
    private class Itr implements Iterator<E> {
//...中略
    }
//...中略
}
```

##匿名クラス(無名クラス)
* **特定の処理をまとめて表すための器**として使う
* ex:イベントリスナー
    * 特定の文脈（ユーザーの動作など）に強く関連するので他では再利用しない
* **`new 基底クラス(引数,...){クラスの本体}`**
    * `new View.OnClickListener(){`
    * 匿名クラスには名前がないのでnew演算子に基底クラス/インターフェースの名前を指定
    * 用意したリスナーのインスタンスにはそのままメソッドに渡せる
* 注意；
    * コンストラクタを持てない（初期化はOK）
    * 継承不可（暗黙的にfinal）
    * 抽象クラス宣言不可

```java
//イベントリスナー登録
btn.setOnClickListener(
  //匿名クラス(イベントリスナー)定義
  new View.OnClickListener(){
    //btnクリックでtxtに現在時刻を表示
    @Override
    public void onClick(View view){
      TextView txt = findViewById(R.id.txtResult);
      txt.setText(LocalDateTime.now().toString());
    }
  }
);
```

##ローカルクラス
* メソッド、コンストラクタなど**ブロック配下で定義されたクラス**
* クラスが特定のメソッド、コンストラクタで利用されるときに使う
* 匿名クラスで代用OK