ソフトウェアエンジニアの日常の雑記

日々思ったことをまとめます

Javaのネスト

Javaのネストって匿名クラスくらいしか使わないけど、まぁ結構色々できるのでまとめ。
間違っていたら指摘お願いします。

import jp.co.sample.NestMaster.StaticInner;

public class NestMaster {
    public static void main(String[] args) {
        String mS = "mS";
        final String mfS = "mfS";

        // call Inner
        NestMaster.Inner inner = new NestMaster().new Inner(); // トップレベルclassをインスタンス化したあとにインナークラスをインスタンス化する 
        inner.show();
        
        // call StaticInner
        NestMaster.StaticInner.staticShow();  // call static method. 
        NestMaster.StaticInner staticInner = new StaticInner();
        staticInner.show(); // call instance method.
        
        Outer outer = new Outer();
        outer.show();
        // call anonymous class method override.
        Outer anonymousOuter = new Outer(){
            @Override
            void show() {
                System.out.println("anonymoutOuter class");
                show2();  // 内部的には呼び出し可能
            };
            void show2() { // クラス内でしか呼び出しできない
                System.out.println(mfS);
                // System.out.println(mS); //Cannot refer to a non-final variable mS inside an inner class defined in a different method
            }; 
            
            
        };
        anonymousOuter.show();
        // outer.show2(); cannot call method
        
        Outer outerMain = new Outer();
        outerMain.main();
    }
    class Inner{
        void show(){
            System.out.println(Inner.class);    
            }
        // static void staticShow(){System.out.println(Inner.class);} // static methods can only be declared in a static or top level type
    }
    
    static class StaticInner{
        String SISI = "SISI";
        final String SIfSI = "SIfSI";
        static void staticShow(){ System.out.println(StaticInner.class);}
        void show(){ System.out.println(StaticInner.class);}
    }
}

class Outer{
    public static void main() {
     // call Inner
        NestMaster.Inner inner = new NestMaster().new Inner(); // トップレベルclassをインスタンス化したあとにインナークラスをインスタンス化する 
        inner.show();
        
        // call StaticInner
        NestMaster.StaticInner.staticShow();  // call static method. 
        NestMaster.StaticInner staticInner = new StaticInner(); // importが必要
        staticInner.show(); // call instance method.
    }
    void show(){System.out.println(Outer.class);}
}

あとで整理しないと読みにくいソースになってしまったが、まとめるとこういうこと。

  • インナークラス
    • トップレベルクラス内にインナークラスが存在する場合
      • クラスとしては普通のクラスと挙動はほぼ同じ
      • インスタンスを作るのにトップレベルクラスのインスタンスも作成しなければならない為、"NestMaster.Inner inner = new NestMaster().new Inner()"のような記述が必要になる。
      • トップレベル内に宣言されているprivateのクラス変数、クラスメソッド、インスタンス変数、インスタンスメソッドにアクセスできる。
    • トップレベルクラス内にインナークラスが存在しない場合
      • 上記のものと同じ
  • staticなインナークラス
    • トップレベルクラス内にいるstaticなインナークラスが存在する場合
      • クラスとしては普通のクラスと挙動はほぼ同じ
      • トップレベルクラスのprivateのクラス変数・クラスメソッドにアクセスできる。(インスタンス変数・インスタンスメソッドは不可)
    • トップレベルクラス内にいるstaticなインナークラスが存在しない場合
      • import文を書かないと呼び出しができない。
      • それ以外は、staticなインナークラスと同じ。
  • 匿名クラス
    • 名前のないクラス
    • 宣言と同時にオブジェクトの生成を行う
    • 自身のクラス名自体存在しない為、他のクラス・インターフェースを継承・実装してインスタンス化する
    • インスタンス化したあとのメソッド呼び出しは、オーバーライドしたものしか使用できない。(匿名クラス内は使用できる)
    • トップレベルクラスの変数呼び出しはfinal宣言されているもののみ呼び出しが可能。