※本サイトで紹介している商品・サービス等の外部リンクには、アフィリエイト広告が含まれる場合があります。

10-10. 内部クラス (inner class)

2023年11月7日

概要

Kotlin の内部クラス (Inner Class) は、他のクラス (外部クラス) の内部に定義されるクラスです。
内部クラスは、外部クラスのメンバにアクセスすることができ、外部クラスとの密接な関係を持つオブジェクトを表現する際に役立ちます。
内部クラスを使用することで、コードのカプセル化を強化し、より柔軟なアクセス制御を実現することができます。

内部クラスとしてではなく、単にクラス内でクラスを宣言することもできますが、内部クラスにより、外部からアクセスできないクラスのカプセル化やコードの見通しをよくする、クラスの関連性を明確化できます。

書式

内部クラスは、キーワード inner で class の前につける形で宣言します。宣言は外部クラスのブロックの内側で行います。

class OuterClass {
    inner class InnerClass {
        ...
    }
}

内部クラスの用途

  • 外部クラスのメンバへのアクセス: 内部クラスは、外部クラスの private なメンバも含めて、すべてのメンバにアクセスすることができます。 これにより、外部クラスの内部状態に基づいて動作するオブジェクトを定義することができます。
  • カプセル化の強化: 内部クラスは、外部クラスの外部からは直接アクセスすることができません。 これにより、外部クラスの内部実装の詳細を隠蔽し、カプセル化を強化することができます。
  • イベントリスナーの実装: GUI プログラミングなどでは、イベントリスナーとして内部クラスを使用することがよくあります。 内部クラスを使用することで、イベントリスナーのコードを外部クラスの近くに記述し、可読性を向上させることができます。

メンバへのアクセス例

クラスの中に inner を用いずにクラスを宣言した場合と、内部クラスを宣言した場合の比較でメンバへアクセスの違いを記載します。

通常のクラスをクラスの中で宣言した場合

通常のクラスをクラスの中で宣言した場合、 内部のクラスは外部クラスのメンバにアクセスすることができません。

内側で宣言した class11 をインスタンス化する際には、class1.class11() でインスタンス化できます。(class11 のコンストラクタが呼び出される。)

class Class1 {
    val property1 = "プロパティ1"

    class Class11 {
        val property11 = "プロパティ11"
        // println(property1) // コンパイルエラー: 単にクラス内でクラスを宣言しただけでは property1 にアクセスできない
    }
}

fun main(){
    val instance1 = Class1.Class11()
    println("instance1.property11 = " + "${instance1.property11}")
}

実行結果

instance1.property11 = プロパティ11

内部クラスを用いた場合

内部クラスを用いた場合、内部クラスは外部クラスのメンバ (private なメンバも含む) にアクセスすることができます。

外側のクラスのコンストラクタ OuterClass() でインスタンス化した後に、内部クラスのコンストラクタ InnerClass() でインスタンス化できます。

val outer = OuterClass()
val inner = outer.InnerClass()
//あるいは
val inner2 = OuterClass().InnerClass()


外側のクラスもインスタンス化されるので、外側のクラスのメンバに this@OuterClass でアクセスできます。

class OuterClass {
    val outerproperty1 = "外部プロパティ"

    inner class InnerClass {
        val innerproperty = "内部プロパティ"
        val outerpropertyFromInterClass = this@OuterClass.outerproperty1  // 外部クラスのプロパティにアクセスできる
    }
}

fun main() {
    val instance2 = OuterClass().InnerClass()
    println("instance2.innerproperty = " + "${instance2.innerproperty}")
    println("instance2.outerpropertyfrominnerclass = " + "${instance2.outerpropertyFromInterClass}")
}

実行結果

instance2.innerproperty = 内部プロパティ
instance2.outerpropertyfrominnerclass = 外部プロパティ