Kotlinのバッキングフィールド及びバッキングプロパティーとは何か
Android開発で人気のKotlinでは、Javaには無いバッキングフィールド及びバッキングプロパティーというコンセプトがあります。これは、Kotlinを学び始めた初心者の方にとって戸惑いがちなトピックです。
この記事では、この二つのコンセプトを簡単な例を使って説明したいともいます。
バッキングフィールド(Backing Field)
簡単に言えば、バッキングフィールドは、プロパティーアクセサ(ゲッターまたはセッター)の内部でのみ使用可能なフィールドです。
Kotlinでは、フィールドを直接宣言することはできません。そのため、バッキングフィールドはアクセサのデフォルト実装を使用している場合、またはカスタムアクセサがフィールドを通して参照される場合にのみ自動生成されます。このバッキングフィールドは、アクセサの再帰的な呼び出しを回避するために使用され、最終的に StackOverflow エラー を防ぐことができます。
では、バッキングフィールドが必要な理由を見てみましょう。
var doubledNumber: Int = 0
get() = doubledNumber
set(value) {
this.doubledNumber = value * 2
}
}
上のコードは、doubledNumber の値を取得しようとすると再帰的にゲッターを呼び出しています。
同様に、doubledNumber の値をセットしようとすると、this.doubleNumber がセッターメソッド内から再びセッターを呼び出すように、同じセッターを再帰的に呼び出してしまいます。
バッキングフィールドを使用することでこれを克服することができます。
上の例のような再帰的なエラーを防ぐために、Kotlinはフィールド識別子を使ってアクセスできる自動バッキングフィールドを提供しています。
var doubledNumber: Int = 0
get() = field
set(value) {
field = value * 2
}
このように、プロパティー名をfield に置き換えることによって、StackOverflow エラーを起こさずにdoubledNumberにアクセスすることができます。
しかし、以下のように、プロパティが全くデフォルトアクセサを実装していない場合、またはカスタムアクセサがフィールド識別子を通してそれを参照していない場合、フィールド識別子は生成されません。
val isEmpty: Boolean
get() = this.size == 0
バッキングプロパティー(Backing Property)
バッキングフィールド機能を使うと、ゲッターやセッターの範囲内でしかプロパティのフィールドにアクセスすることができません。ゲッターやセッターを使わずに直接アクセスしたい場合には、バッキングプロパティ機能を使うべきです。
バッキングプロパティーは、ゲッターやセッター外でフィールドに直接アクセスしたいときなどに使われ、private フィールドに_を付けて明示されます。
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap()
}
return _table ?: throw AssertionError("他のスレッドによってnullにセットされました。")
}
上の例を見ると、バッキングプロパティ機能を使うことで、フィールドに直接アクセスできることがわかります。
この記事が、バッキングフィールドとバッキングプロパティの理解を深める上で、多少なりともお役に立てたのであれば幸いです。Kotlinにはそんな便利な機能が満載です。公式ドキュメントを自分で見てみることをお勧めします。
この記事が気に入ったらサポートをしてみませんか?