インナークラスとは(ローカルクラスと匿名クラス)Java初心者の勉強

2020-11-23

インナークラスについて調べます。

インナークラスの前に

インナークラスの前にネストされたクラス(Nested Classes)について簡単に説明します。
ネストされたクラスとはクラス(外側のクラス/ Outer Class)の中にあるクラス(Nested Class)のことを言います。

class OuterClass
{
 // any code
    class NestedClass
    {
         // any code
    }
}

クラスの内部にクラスを作ることでグループ化し読みやすくしたりカプセルかしたりメンテナンスしやすくしています。
ネストされたクラスには以下のように種類があります。

ネストされたクラス一覧

大きくは以下の2つに分けられます。

  • Static(静的)ネストクラス
  • Non-static(非静的)ネストクラス / inner classes(インナークラス)

ここででてくるNon-static(非静的)ネストクラスが別名インナークラスと呼ばれています。

インナークラスとは

ネストされたクラスでstaticでないクラスをインナークラスと呼びます。
インナークラスのアクセス修飾子をprivateにするとクラスの外から呼び出せなくなります。(カプセル化)

※クラスに宣言された フィールド と メソッド のことをメンバーと言うことからメンバークラスと呼ばれたりもするようです。

上記の図にもありますがインナークラスには以下の種類があります。

  • ローカルクラス (Local classes)
  • 無名/無名クラス(Anonymous classes)

※インナークラスは和訳すると内部クラスとなります。

ローカルクラス (Method-Local classes / Local classes)とは

ローカルクラスはメソッド中に書かれたクラスのことを言います。
クラスのバックグランド的な処理を実行することに使われたりするようです。
インナークラスのスコープはメソッド内で制限されます。
またインナークラスが定義されているメソッド内でのみインスタンス化できます。

サンプルコード

ローカルクラスのサンプルコードです。コメントを利用して解説しています。

※dokojavaを使用してテストしています。

import java.util.*;

public class Outerclass {
   // メソッドを作成
   void my_Method() {
      int num = 100;

      // ローカルクラスの作成
      class MethodLocal{
      //メソッド作成
         public void print() {
            System.out.println("ローカルクラスのメソッドを呼び出しOuterclassのintの値を表示:"+num);
         }  
      }

      // ローカルクラスへアクセス
      MethodLocal inner = new MethodLocal();
      inner.print();
   }

   public static void main(String args[]) {
   //外側のインスタンスの生成
      Outerclass outer = new Outerclass();
      //メソッドの呼び出し
      outer.my_Method();
   }
}

結果

ローカルクラスのメソッドを呼び出しOuterclassのintの値を表示:100

無名/匿名クラス(Anonymous classes)とは

匿名クラスはその名の通り名前の無いクラスのことを言います。
インターフェースやクラスの1度しか使用しないようなその場限りのメソッドををオーバーロードする際に使用されます。
匿名クラスは以下のような部分です。

new インターフェイス名() { // code }

サンプルコード 通常の書き方

無名クラスはわかりづらいので通常の場合と比較してみます。

interface Age{
    int x = 20;
    void getAge();
}

class Outerclass{
    public static void main(String[] args)  {
        // NonAnonymousクラスのインスタンスを生成して変数へ代入
        NonAnonymous obj = new NonAnonymous();

        // NonAnonymousのgetage() メソッドを呼び出し
        obj.getAge();      
    }
}

// Ageインターフェースを実装した NonAnonymous クラスを作成
class NonAnonymous implements Age{ // 匿名クラスを使用しない場合
    @Override
    public void getAge()  {
        // 年齢を表示
        System.out.print("年齢は "+x);
    }
}

結果

年齢は20

匿名クラスをしようしないと少し長いです。

サンプルコード 匿名クラスを使用した書き方

結果とインターフェースは上記と同じため省略。

class Outerclass{
    public static void main(String[] args) {
          // インターフェースを生成して匿名クラスで実装したもの代入
          Age obj = new Age(){ //匿名クラス開始
             //メソッドをオーバーライド
              @Override
             public void getAge()  {
                 // 年齢を表示
                 System.out.print("年齢は "+x);
            }
        };
        // getage() メソッドを呼び出し
        obj.getAge();      
    }
}

「クラスの宣言」と「インスタンスの生成」を同時に行うことができるためコードが少なくなります。

サンプルコード 匿名クラスを使用した書き方 (変数に値を返さない場合)

結果とインターフェースは省略。

class Outerclass{
    public static void main(String[] args)  {
        // 変数に代入なしでインターフェースを生成
        new Age(){ //匿名クラス開始
           //メソッドをオーバーライド
           @Override
          public void getAge()  {
              // 年齢を表示
              System.out.print("年齢は "+x);
          }
       }.getAge(); //メソッド呼び出し
    }
}

おまけ  Static(静的)ネストクラス

せっかくなので簡単にStatic(静的)ネストクラス のサンプルコードも貼り付けておきます。

public class Outerclass {
   static class Nestedclass {
      public void method() {
         System.out.println("Static(静的)ネストクラスのメソッドが呼び出されました。");
      }
   }
   public static void main(String args[]) {
      Outerclass.Nestedclass obj = new Outerclass.Nestedclass();
      obj.method();
   }
}

結果

Static(静的)ネストクラスのメソッドが呼び出されました。

おわり

インナークラスの呼び出し方が複雑に感じてしまいますね。ローカルクラスに関してはあまり使っていないと書いている人もいたのでしばらくはこんなのもあるんだ程度で深追いしないでおこうと思います。
インナークラスを調べていると名称が日本語のサイトを見ていると和訳の問題なのかサイトによって異なることもあって混乱したので基本的に英語のサイトを参考に書きました。
日本だと名称が変わって定着しているなんてことってあるんでしょうか。

参考