web-dev-qa-db-ja.com

Kotlinクラスの初期化セマンティクスとは何ですか?

Kotlinでのクラスの初期化を説明する言語定義には何も見つかりませんでした。

import Java.util.Properties

fun main(args: Array<String>) {
    val out = MyClass()
    out.fn()
}

class MyClass {
    private val a = Properties() // 1

    init {
        fn()
    }

    public fun fn() {
        println("Fn called.  a = $a")
    }

    //  private val a = Properties() // 2
}

このプログラムを実行した結果は、プロパティが(1)で初期化されるか(2)で初期化されるかによって異なります。

宣言の順序がその言語に関連していることに驚いており、その背後にある決定を理解したいと思います。私の期待は、コンストラクター本体が呼び出される前にプロパティが初期化されることです。

14
Nigel Eke

私の期待は、コンストラクター本体が呼び出される前にプロパティが初期化されることです。

さて、initブロックは コンストラクター ではありません。これは、オブジェクトの初期化を実行できるようにする別の構成であり、[initブロック]はプロパティ初期化子を使用して宣言順に実行されます。

コンストラクターは、すべてのプロパティが初期化され、すべてのinitブロックが実行された後に実行される別の獣です。次の例を見てください。

class A(val value: Int) {
    constructor(): this(0) {        
        println("Constructor")
    }    

    init {
        println("Init block")
    }
}

fun main(args: Array<String>) {
    val a = A()
}

出力は次のとおりです。

Init block  
Constructor

initブロックはどこにでも配置できます。constructorの前または後。常にbeforeAのコンストラクター(この例では2次コンストラクター)で実行されます。

15
aga

簡単に言えば、クラスのインスタンスが作成されると、(ほぼ)最初に親クラスのコンストラクター(存在する場合)が実行され、次にプライマリコンストラクターが実行されます。

プライマリコンストラクタは、クラス本体で宣言されたコードを上から下に実行します。また、名前は同じルールで使用可能になりました。

class Foo(a: String = "might be first"
          val b: String = "second" + a) : Boo(a + b + "third"){
    var c = a + "fourth" + b

    init {print("fifth: $c")}

    val d = "sixth"
    init {print("seventh: the end of the primary constructor"}
}

セカンダリコンストラクターを呼び出すと、チェーンで構成されているため、プライマリコンストラクターの後に機能します(親コンストラクターの呼び出しと同様)。

5
voddan