見出し画像

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にはそんな便利な機能が満載です。公式ドキュメントを自分で見てみることをお勧めします。


この記事が気に入ったらサポートをしてみませんか?