【Java Gold】4種類のネストされたクラスの特徴についてまとめてみた

## 記事作成の経緯
現在、Java SE 11 Programmer II試験(以下Java Gold)に向けて勉強をしているのですが、参考書をある程度読み込みましたので、問題集への取り掛かりと並行してアウトプットをしていこうと思い、記事を作成しています。
自分はアウトプットを目的として書いていますが、どこかにいるであろう同じ試験への合格・挑戦を目指している方への参考になるような記事作成を心掛けていきます。
記事は「[オラクル認定資格教科書 Javaプログラマ Gold SE11(山本道子　著)](https://www.shoeisha.co.jp/book/detail/9784798170572) 」(いわゆる紫本)を参考に作成しております。

## 今回紹介する内容
今回はおそらくJava Goldを勉強する際、最初に苦労するであろうネストされたクラスについて紹介していこうと思います。

## ネストされたクラスとは
ネストクラスとは一言で表すと<strong>「クラス定義の中に定義されたクラス」</strong>です。クラス定義は通常、Javaファイル内で行われクラスの中に変数やメソッドを定義していきます。クラス内に定義された変数やメソッドを総称してメンバを呼びますが、ネストされたクラスもメンバに含まれます。

## ネストされたクラスの種類と特徴
一言にネストされたクラスといっても、定義される場所や修飾子によって名前や特徴、呼び出し方が変わってきます。主な種類は以下の4つになります。
* インナークラス(非staticクラス)
* staticクラス
* ローカルクラス
* 匿名クラス(無名クラス)

それでは各クラスについてみていきましょう。

### インナークラス(非staticクラス)
インナークラス（非staticクラス）は、外側クラスのインスタンスに関連付けられたクラスです。これにより、インナークラスは外側クラスのメンバに直接アクセスできます。特徴として以下の点が挙げられます。
* 外側クラスと同じクラス名を使用できない
* アクセス修飾子を使用できる
* abstract修飾子、final修飾子を使用できる
* インナークラスでは外側クラスのインスタンスを必要とする
* インナークラスでは外側クラスのインスタンスメンバ、staticメンバにアクセスできる
* インナークラスでは<strong>staticメンバを定義することはできない</strong>

それではコードを確認していきます
```Main.java
class Outer{
    String inStrO = "InStrO";
    static String stStrO = "stStrO";
    public class Inner{
        String inStrI = "InStrI";
      //static String stStrI = "stStrI";  //1,staticメンバは定義できない
        void innerMethod(){
            System.out.println(inStrO);  //2,外側クラスのインスタンスメンバへのアクセス
            System.out.println(stStrO);  //3,外側クラスのstaticメンバへのアクセス
            System.out.println(inStrI);
        }
    }
}

public class Main {
    public static void main(String[] args){
    //4,外側クラスのインスタンスを必要としている
        Outer.Inner inner = new Outer().new Inner();
        inner.innerMethod();
    }
}
```
```出力結果.console
InStrO
stStrO
InStrI
```

### staticクラス
staticクラスは外側クラスの静的メンバとして定義されるクラスです。また、staticクラスは、外側クラスのインスタンスを必要としません。特徴として以下の点が挙げられます。
* 外側クラスと同じクラス名を使用できない
* アクセス修飾子を使用できる
* abstract修飾子、final修飾子を使用できる
* staticクラスでは外側クラスのインスタンスを必要としない
* staticクラスでは外側クラスの<strong>静的メンバ(staticメンバ)にのみ</strong>アクセスできる
* staticクラスでは非staticメンバ、staticメンバを定義することができる

それではコードを確認していきます
```Main.java
class Outer{
    static String strO = "outer";
    public static class Inner{
        static String strI = "inner";  //1,staticなメンバの定義
        void innerMethod(){
            System.out.println(strO);  //2,外側クラスのstaticメンバへのアクセス
            System.out.println(strI);
        }
    }
}

public class Main {
    public static void main(String[] args){
    //3,外側クラスのインスタンスを必要としていない
        Outer.Inner inner = new Outer.Inner();
        inner.innerMethod();
    }
}
```
```出力結果.console
outer
inner
```

### ローカルクラス
ローカルクラスはメソッド内で定義されるクラスであり、ローカルクラスを定義したメソッドのローカル変数と同じスコープを持ちます。特徴として以下の点が挙げられます。
* アクセス修飾子を使用できない
* staticなクラスとして定義できない
* abstract修飾子、final修飾子を使用できる
* 外側クラスのメンバにアクセスできる(非static,static問わない)
* メソッドの引数やローカル変数にアクセスできるが、変数はfinalもしくは実質的なfinalでなければならない
* ローカルクラスではstaticメンバを定義できない

それではコードを確認していきます
```Main.java
class Kokoa{
    String inStr = "inStr";
    static String stStr = "stStr";
    void method1(int num,final int num2){
        int num3 = 3;
        final int num4 = 4;
        class Kakao{
            void method2(){
                int num5 = 5;
              //static int num6 = 6;  //1,staticなメンバの定義はできない
                System.out.println(inStr);  //2,外側クラスのインスタンスメンバへのアクセス
                System.out.println(stStr);  //3,外側クラスのstaticメンバへのアクセス
                System.out.println(num);  //4,メソッドの引数へのアクセス(実質的final)
                System.out.println(num2);  //5,メソッドの引数へのアクセス(final)
                System.out.println(num3);  //6,ローカル変数へのアクセス(実質的final)
                System.out.println(num4);  //7,ローカル変数へのアクセス(final)
                System.out.println(num5);
            }
        }
        new Kakao().method2();  //8,インスタンスの作成とメソッドの実行
    }
}

public class Main {
    public static void main(String[] args) {
        Kokoa kokoa = new Kokoa();
        kokoa.method1(1,2);
    }
}
```
```出力結果.console
inStr
stStrO
1
2
3
4
5
```

###　匿名クラス(無名クラス)
匿名クラス（無名クラス）は、一度だけ使用されるインスタンスを作成するためのクラスです。また、名前を持たないため宣言と同時にインスタンス化されます。特徴として以下の点が挙げられます。

* アクセス修飾子を使用できない
* static修飾子を使用できない
* abstract修飾子、final修飾子を使用できない
* 外側クラスのメンバにアクセスできる(非static,static問わない)
* メソッドの引数やローカル変数にアクセスできるが、変数はfinalもしくは実質的なfinalでなければならない
* 匿名クラスでは、インターフェースまたは既存のクラスを実装または継承する
* コンストラクタは定義できない

それではコードを確認していきます
```Main.java
interface Drink{void taste();}
class Kokoa{
    String inStr = "inStr";
    static String stStr = "stStr";
    void method1(int num,final int num2){
        int num3 = 3;
        final int num4 = 4;
        //匿名クラスでのインターフェースの実装
        new Drink(){
            int num5 = 5;
            //static int num6 = 6;  //1,staticなメンバの定義はできない
            public void taste(){
                System.out.println(inStr);  //2,外側クラスのインスタンスメンバへのアクセス
                System.out.println(stStr);  //3,外側クラスのstaticメンバへのアクセス
                System.out.println(num);  //4,メソッドの引数へのアクセス(実質的final)
                System.out.println(num2);  //5,メソッドの引数へのアクセス(final)
                System.out.println(num3);  //6,ローカル変数へのアクセス(実質的final)
                System.out.println(num4);  //7,ローカル変数へのアクセス(final)
                System.out.println(num5);
            }
        }.taste();
    }
}

public class Main {
    public static void main(String[] args) {
        Kokoa kokoa = new Kokoa();
        kokoa.method1(1,2);
    }
}
```
```出力結果.console
inStr
stStr
1
2
3
4
5
```
## 終わりに
今回は、ネストされたクラスの種類を特徴について紹介しました。見慣れないうちは難しいと感じるかもしれませんが、何度も復習していくうちに覚えられますのでめげずに頑張ってください。また、Javaのstaticとはどういうものなのか、ネストされたクラスはどのようなときに使われるのか、なども改めて調べてみると感覚的に覚えやすくなるかもしてません(個人の感想)。
以上！