2

lazy valを使用して、オーバーライドされたメンバー値をスーパークラス コンストラクターに伝達する方法に関するこの説明を見つけました。残念ながら、この記事では、これが機能する理由について説明していません。

変数を別の値にロックしないためには、スーパー クラス コンストラクターでの値の割り当てをスキップする必要があるため、非遅延値を 2 回割り当てることはできないため、スーパー コンストラクターでは値を使用できないことを理解しています。しかし、新しい遅延値が割り当てられる前にスーパー コンストラクターで実行されるprintlnステートメントは、どのようにしてこの新しい値を認識できるのでしょうか。実行順序について何か混乱していますか? それとも、printlnは、オブジェクトが構築された後にその引数を評価するだけですか?

4

1 に答える 1

7

とてもシンプルです。すべてのフィールドとレイジー フィールドはゲッター メソッドであることに注意してください。

valgetter はprivate[this]フィールドの値を返します。private[this]フィールドの割り当ては、プライマリ コンストラクターにあります。

class Test {
  val field = 1
}

次のような意味です。

class Test {
  private[this] val _field: Int = _
  def field = _field

  {  // constructor
    _field = 1
  }
}

したがって、コンストラクターfieldがデフォルト値を返す前に。

lazy valダブルチェックロックを使用してコードブロックを評価し、結果を返します。

class Test {
  lazy val field = 1
}

次のような意味です。

class Test {
  private[this] val _field: Int = _
  @volatile private[this] val _flag: Boolean = _

  def field = {
    if (! _flag) {
      synchronized {
        if (! _flag) {
          _field = 1 // code block
          _flag = true
        }
      }
    }

    _field
  }
}

コンストラクlazy valターには何もないため、コンストラクターの前後で同じ結果が得られます。

を使用してこれを確認できscalac -Xprint:mixin test.scalaます。

于 2013-08-04T20:36:27.533 に答える