クラスの実装 〜 プロパティとバッキングフィールド
Kotlin でプロパティを定義する場合、次のように記述できます。
class Person { private var _text: String = "" var name: String get() { return _text } set(value) { _text = value } }
この Person クラスでは name というプロパティを公開しています。 そして、そのプロパティの値は Person 内部では _text というメンバー変数に保存しています。
このように、あるプロパティの値を保持するデータストレージ (ここではメンバー変数) のことを、バッキングフィールド (backing field) といいます。
プロパティのゲッターとセッターは次のように、プロパティ名に続き get() と set(value) を書くことで記述できます。
var name: String get() { return _text } set(value) { _text = value }
プロパティ名に続く、get() ではそのプロパティの値を返すように実装します。 また、set(value) は、外部からそのプロパティに値をセットした時に、value に自動的に値が入ります。 この値をバッキングフィールド (ここでは _text メンバ変数) にセットできます。
この Person クラスを使う側では、次のようにプロパティを使えます。
fun main() { val p = Person() p.name = "Mike" println(p.name) // "Mike" }
暗黙的なバッキングフィールドの生成と field キーワード
Kotlin ではバッキングフィールドを明示的に作成しなくとも、必要に応じて自動的に生成することができます。
上と同様のコードは、Kotlin では次のようにも記述できます。
class Person { var name: String = "" get() { return field } set(value) { field = value } }
どこが変わったでしょうか。
まず、バッキングフィールドとして明示的に用意した、_text メンバーがありませんね。 その代わり、field というキーワードが登場しています。これはなんでしょうか。
Kotlin では、あるプロパティを実装するために必要なバッキングフィールドは必要に応じて暗黙的に自動生成され、ゲッターとセッターで field というキーワードでそれにアクセスできるのです。
もうひとつの違いとして、プロパティ名と型に続いて、バッキングフィールドの初期化をおこおなっています。ここでは = "" として、空文字に設定しています。
バッキングフィールドを明示的に作成しなくても良いだけでも、だいぶスッキリしましたが、実は上のコードはさらに簡潔に記述できます。
このゲッター get() やセッター set(value) は、単純にバッキングフィールドの値を返したり、set(value) で受け取った値を単純に field にセットしているだけです。 このような場合は、ゲッターとセッターは省略可能です。
省略可能なものを省略すると、上と同じ Person クラスと同じ働きをするクラスは、次のようにかけます。
class Person { var name: String = "" }
繰り返しになりますが、この定義だけ見ると、あたかも name という名前の変数を作り、それに外部からアクセスしているように見えますが、 実際は背後にバッキングフィールドが作成されており、それにはゲッターやセッターから field というキーワードでアクセスできる、という仕組みになっています。