Javaの入れ子クラス

Javaのネストされたクラス

1. 前書き

このチュートリアルは、Java言語のネストされたクラスの簡単でわかりやすい紹介です。

簡単に言えば、Javaを使用すると、他のクラス内にクラスを定義できます。 Nested classes enable us to logically group classes that are only used in one place, write more readable and maintainable code and increase encapsulation.

始める前に、この言語で使用できるネストされたクラスのいくつかのタイプを見てみましょう。

  • 静的なネストされたクラス

  • 非静的なネストされたクラス

  • ローカルクラス

  • 匿名クラス

次のセクションでは、これらのそれぞれについて詳しく説明します。

2. 静的なネストされたクラス

静的なネストされたクラスについて覚えておくべきポイントがいくつかあります。

  • 静的メンバーと同様に、これらはクラスのインスタンスではなく、それらを囲むクラスに属します

  • 宣言にすべてのタイプのアクセス修飾子を含めることができます

  • 外側のクラスの静的メンバーのみにアクセスできます

  • 静的メンバーと非静的メンバーの両方を定義できます

静的なネストされたクラスを宣言する方法を見てみましょう。

public class Enclosing {

    private static int x = 1;

    public static class StaticNested {

        private void run() {
            // method implementation
        }
    }

    @Test
    public void test() {
        Enclosing.StaticNested nested = new Enclosing.StaticNested();
        nested.run();
    }
}

3. 非静的ネストクラス

次に、非静的なネストされたクラスについて覚えておくべきいくつかの簡単なポイントを次に示します。

  • 内部クラスとも呼ばれます

  • 宣言にすべてのタイプのアクセス修飾子を含めることができます

  • インスタンス変数やメソッドと同様に、内部クラスは囲んでいるクラスのインスタンスに関連付けられます

  • それらは、静的か非静的かに関係なく、包含クラスのすべてのメンバーにアクセスできます。

  • 非静的メンバーのみを定義できます

内部クラスを宣言する方法は次のとおりです。

public class Outer {

    public class Inner {
        // ...
    }
}

修飾子staticを使用してネストされたクラスを宣言すると、それは静的メンバークラスになります。 それ以外の場合は、内部クラスです。 構文的には違いは単一のキーワード(つまり、static)ですが、意味的には、これらの種類のネストされたクラスの間には大きな違いがあります。 内部クラスのインスタンスは、それを囲むクラスのインスタンスにバインドされているため、メンバーにアクセスできます。 ネストされたクラスを内部クラスにするかどうかを選択するときは、この問題に注意する必要があります。

内部クラスをインスタンス化するには、最初にそれを囲むクラスをインスタンス化する必要があります。

それを行う方法を見てみましょう。

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();

次のサブセクションでは、いくつかの特別なタイプの内部クラスを示します。

3.1. ローカルクラス

ローカルクラスは特殊なタイプの内部クラスであり、the class is defined inside a methodまたはスコープがブロックされます。

このタイプのクラスについて覚えておくべきいくつかのポイントを見てみましょう。

  • 宣言にアクセス修飾子を含めることはできません

  • 囲んでいるコンテキストの静的メンバーと非静的メンバーの両方にアクセスできます

  • インスタンスメンバーのみを定義できます

以下に簡単な例を示します。

public class NewEnclosing {

    void run() {
        class Local {

            void run() {
                // method implementation
            }
        }
        Local local = new Local();
        local.run();
    }

    @Test
    public void test() {
        NewEnclosing newEnclosing = new NewEnclosing();
        newEnclosing.run();
    }
}

3.2. 匿名クラス

匿名クラスを使用すると、再利用可能な実装を作成することなく、インターフェイスまたは抽象クラスの実装を定義できます。

匿名クラスについて覚えておくべきいくつかのポイントをリストしましょう。

  • 宣言にアクセス修飾子を含めることはできません

  • 囲んでいるコンテキストの静的メンバーと非静的メンバーの両方にアクセスできます

  • インスタンスメンバーのみを定義できます

  • これらは、コンストラクターを定義したり、他のクラスやインターフェースを拡張/実装したりできない、ネストされたクラスの唯一のタイプです。

匿名クラスを定義するには、最初に単純な抽象クラスを定義しましょう。

abstract class SimpleAbstractClass {
    abstract void run();
}

次に、匿名クラスを定義する方法を見てみましょう。

public class AnonymousInnerTest {

    @Test
    public void whenRunAnonymousClass_thenCorrect() {
        SimpleAbstractClass simpleAbstractClass = new SimpleAbstractClass() {
            void run() {
                // method implementation
            }
        };
        simpleAbstractClass.run();
    }
}

詳細については、Anonymous Classes in Javaに関するチュートリアルが役立つ場合があります。

4. シャドーイング

同じ名前の場合はThe declaration of the members of an inner class shadow those of the enclosing class

この場合、thisキーワードはネストされたクラスのインスタンスを参照し、外部クラスのメンバーは外部クラスの名前を使用して参照できます。

簡単な例を見てみましょう:

public class NewOuter {

    int a = 1;
    static int b = 2;

    public class InnerClass {
        int a = 3;
        static final int b = 4;

        public void run() {
            System.out.println("a = " + a);
            System.out.println("b = " + b);
            System.out.println("NewOuterTest.this.a = " + NewOuter.this.a);
            System.out.println("NewOuterTest.b = " + NewOuter.b);
            System.out.println("NewOuterTest.this.b = " + NewOuter.this.b);
        }
    }

    @Test
    public void test() {
        NewOuter outer = new NewOuter();
        NewOuter.InnerClass inner = outer.new InnerClass();
        inner.run();

    }
}

5. 直列化

ネストされたクラスをシリアル化しようとしているときにjava.io.NotSerializableExceptionを回避するには、次のことを行う必要があります。

  • ネストされたクラスをstaticとして宣言します。

  • ネストされたクラスとそれを囲むクラスの両方にSerializableを実装させます

6. 結論

この記事では、ネストされたクラスとは何か、およびそれらのさまざまなタイプについて説明しました。 また、フィールドの可視性とアクセス修飾子がそれらの異なるタイプ間でどのように異なるかを調べました。

いつものように、このチュートリアルの完全な実装はover on GitHubにあります。