内部クラスはあまり理解しやすいものではありませんが、要するに、あるクラスの中に別のクラスが含まれているということです。

例えるなら、人間は脳、四肢、臓器などの身体構造から成り立っており、内部クラスはその中の特定の臓器に相当します。例えば心臓:心臓にも独自の属性と動作(血液、鼓動)があります。

明らかに、ここでは属性やメソッドだけで心臓を表すことはできず、クラスが必要です。

そして心臓は人体の中にあります。それは内部クラスが外部クラスの中にあるのとまったく同じです。

例1:内部クラスの基本構造

//外部类
class Out {
    private int age = 12;
     
    //内部类
    class In {
        public void print() {
            System.out.println(age);
        }
    }
}
 
public class Demo {
    public static void main(String[] args) {
        Out.In in = new Out().new In();
        in.print();
        //或者采用下种方式访问
        /*
        Out out = new Out();
        Out.In in = out.new In();
        in.print();
        */
    }
}

実行結果:12

上記の例からも分かるように、内部クラスは実際には良いコード構造を著しく壊します。しかし、それでも内部クラスを使うのはなぜでしょうか?

なぜなら、内部クラスは外部クラスのオブジェクトを生成しなくても、外部クラスのメンバー変数(private を含む)を自由に使用できるからです。これも内部クラスの唯一の利点です。

これは、心臓が体の血液に直接アクセスでき、医者が採血する必要がないのと同じです。

プログラムをコンパイルすると、Out.class と Out$In.class という2つの .class ファイルが生成されます。

このうち $ は、上記のプログラムの Out.In の間の「.(ドット)」を表しています。

Out.In in = new Out().new In()これを使用して内部クラスのオブジェクトを生成できます。この方法には、注意すべき小さなポイントが2つあります。

  • 1. 先頭の Out は、生成する内部クラスのオブジェクトがどの外部クラスに属するかを示すためのものです。
  • 2. 内部クラスのオブジェクトを生成するには、先に外部クラスのオブジェクトが存在する必要があります。内部クラスの役割は外部クラスのメンバー変数にアクセスすることだからです。
class Out {
    private int age = 12;
     
    class In {
        private int age = 13;
        public void print() {
            int age = 14;
            System.out.println("局部变量:" + age);
            System.out.println("内部类变量:" + this.age);
            System.out.println("外部类变量:" + Out.this.age);
        }
    }
}
 
public class Demo {
    public static void main(String[] args) {
        Out.In in = new Out().new In();
        in.print();
    }
}

実行結果:

局部变量:14
内部类变量:13
外部类变量:12

例1から分かるように、内部クラスは、同名のメンバー変数やローカル変数がない場合、外部クラスのメンバー変数に直接アクセスでき、指定する必要はありません。Out.this.属性名。

そうでない場合、内部クラス内のローカル変数が外部クラスのメンバー変数を上書きします。

一方、内部クラス自体のメンバー変数にアクセスするには、this.属性名、外部クラスのメンバー変数にアクセスするにはOut.this.属性名。

例3:静的内部クラス

class Out {
    private static int age = 12;
     
    static class In {
        public void print() {
            System.out.println(age);
        }
    }
}
 
public class Demo {
    public static void main(String[] args) {
        Out.In in = new Out.In();
        in.print();
    }
}

実行結果:12

分かるように、static で内部クラスを静的化すると、内部クラスは外部クラスの静的メンバー変数にしかアクセスできず、制約があります。

次に、内部クラスが静的化されているため、Out.In を一つのまとまりとして扱うことができ、直接 new で内部クラスのオブジェクトを生成できます(クラス名を通じて static にアクセスするため、外部クラスのオブジェクトを生成するかどうかは関係ありません)。

例4:プライベート内部クラス/h3>
class Out {
    private int age = 12;
     
    private class In {
        public void print() {
            System.out.println(age);
        }
    }
    public void outPrint() {
        new In().print();
    }
}
 
public class Demo {
    public static void main(String[] args) {
        //此方法无效
        /*
        Out.In in = new Out().new In();
        in.print();
        */
        Out out = new Out();
        out.outPrint();
    }
}

実行結果:12

もし内部クラスを外部クラスのメソッドからのみ操作したい場合は、private で内部クラスを宣言することができます。

上記のコードでは、Out クラスの中で In クラスのオブジェクトを生成して操作する必要があり、Out.In in = new Out().new In()内部クラスのオブジェクトを生成するために使用することはできません。

つまり、このときの内部クラスは外部クラスだけが制御できます。

例えるなら、私の心臓は私の体によってのみ制御され、他の人は直接アクセスできません。

例5:メソッド内部クラス

class Out {
    private int age = 12;
 
    public void Print(final int x) {
        class In {
            public void inPrint() {
                System.out.println(x);
                System.out.println(age);
            }
        }
        new In().inPrint();
    }
}
 
public class Demo {
    public static void main(String[] args) {
        Out out = new Out();
        out.Print(3);
    }
}

実行結果:

3
12

上記のコードでは、内部クラスを外部クラスのメソッド内に移動し、外部クラスのメソッド内で内部クラスのオブジェクトを生成して、内部クラスのメソッドを呼び出します。

このとき、外部クラスのメソッドにパラメータを渡す必要がある場合、外部クラスのメソッドの仮引数は final で定義する必要があります。

final はここでは特別な意味を持たず、単なる表現形式にすぎません。