Kotlinのコンストラクタ

プライマリコンストラクタ

クラス名の後の括弧内にプライマリコンストラクタに渡す引数を定義することができます。プライマリコンストラクタに引数を渡す必要がない場合は省略可能です。プライマリコンストラクタに渡した引数は、プロパティの宣言と初期化ブロックの中でアクセスすることが可能です。

class Person constructor(name: String) {
    val name: String = name
}

以下の例では、初期化ブロックにおいてプライマリコンストラクタで渡された引数を出力した後、プロパティに代入しています。

class Person constructor(name: String) {
    val name: String

    init {
        println("set name as $name")
        this.name = name
    }
}

プライマリコンストラクタに渡された引数をそのままプロパティとして宣言することも可能です。この場合、引数名の前にアクセス修飾子とvalキーワードまたはvarキーワードを与えます。この表記には、プロパティの宣言と代入を一箇所で完結できるためコードが簡潔になるという利点があります。特別な理由がなければ、この記法を用います。

class Person constructor(
    val name: String
)

プライマリコンストラクタのconstructorキーワードは省略することが可能です。特別な理由がなければ、constructorキーワードは省略した方が簡潔なコードとなります。

class Person (
    val name: String
)

セカンダリコンストラクタ

Kotlinでは、プライマリコンストラクタに加えて、クラス本体においてセカンダリコンストラクタを定義することが可能です。

以下の例では、引数なしでPersonクラスをインスタンス化した場合に、デフォルトの値を使ってPersonクラスをインスタンス化しています。セカンダリコンストラクタからプライマリコンストラクタを呼び出しています。

class Person (
    val name: String
) {
    constructor() : this("no name")
}

セカンダリコンストラクタは、引数の数や型が異なれば、複数宣言することも可能です。以下の例では、上記の例で宣言したセカンダリコンストラクタに加えて、String型の引数を2つ定義したセカンダリコンストラクタを宣言しています。

class Person (
    val name: String
) {
    constructor() : this("no name")

    constructor(firstName: String, lastName: String) : this("$firstName $lastName")
}

プライマリコンストラクタと異なり、セカンダリコンストラクタは、コンストラクタ本体を持つことも可能です。コンストラクタ本体は、それが定義されるコンストラクタが呼び出された時に処理されます。

class Person (
    val name: String
) {
    constructor() : this("no name") {
        println("constructor with no name")
    }

    constructor(firstName: String, lastName: String) : this("$firstName $lastName") {
        println("constructor with first name and last name")
    }
}

Kotlinではプライマリコンストラクタにデフォルト引数を定義することが可能であるため、セカンダリコンストラクタが必要とされる機会は限定的です。

初期化ブロック

クラス本体においてinitキーワードを用いることで、初期化ブロックを宣言することが可能です。初期化ブロック内には、インスタンスの初期化処理を定義します。

class Person (
    val name: String
) {
    init {
        doSomethingHere()
    }
}

初期化ブロックは複数定義することが可能です。初期化ブロックを複数定義した場合は、上から宣言した順に呼び出されます。

class Person (
    val name: String
) {
    init {
        doSomethingHere()
    }

    init {
        doAnotherThingHere()
    }
}

セカンダリコンストラクタのコンストラクタ本体と初期化ブロックが同時に宣言されている場合には、初期化ブロック、コンストラクタ本体の順に呼び出されます。

筆者

茨城県つくば市在住のソフトウェアエンジニアです。得意領域はAndroidとFlutterです。「Jetpack ComposeによるAndroid MVVMアーキテクチャ入門」の著者です。

👉もっと詳しく