プロパティの宣言
Kotlinのクラスは、プロパティを持つことができます。 これらは、 var キーワードを使用して、ミュータブル(可変)として宣言することもでき、 val キーワードを使用するとイミュータブル(読み取り専用)にすることもできます。
プロパティを使うにはJavaでのフィールドでやるように、ただ単純に名前で参照するだけで良いです:
ゲッターとセッター
プロパティを宣言するための完全な構文は次のとおりです
イニシャライザ、ゲッターとセッターは必須ではありません。イニシャライザか基本クラスのメンバーからオーバライドされることが推測される場合は、プロパティの型も必須ではありません。
例:
読み取り専用のプロパティ宣言の完全な構文は、ミュータブルのものと比べて2点異なります。var の代わりに val で始まるのと、セッターを認めないことでです:
カスタムアクセサは普通の関数ととても似ていて、プロパティの中に宣言することができます。ここでは、カスタムゲッターの例を示します:
カスタムセッターは次のようになります:
慣例により、セッターの引数名は value ですが、別の名前が良いならそちらを選択することもできます。
アクセサの可視性を変更したり、アノテーションを付ける必要がありますが、デフォルトの実装を変更する必要がない場合は、その本体を定義せずにアクセサを定義することができます:
var setterWithAnnotation: Any? = null
@Inject set // セッターに Inject でアノテーションを付ける
バッキングフィールド (Backing Fields)
Kotlinのクラスは、フィールドを持つことができません。しかし、カスタムアクセサを使用するときにバッキングフィールドが必要になることがあります。この目的のために、Kotlinは自動バッキングフィールドを提供します。これにより、 field 識別子を使用してアクセスすることができます。
field 識別子は、プロパティのアクセサにのみ使用することができます。
プロパティがアクセサのデフォルトの実装のうち少なくとも1つを使用するか、カスタムアクセサが field 識別子を通して参照された場合に、バッキングフィールドは生成されます。
たとえば、以下のような場合にはバッキングフィールドは存在しません:
バッキングプロパティ
「暗黙のバッキングフィールド」にそぐわないことをやりたい場合には、 バッキングプロパティ (backing property) を持つように必ずフォールバックさせることもできます:
全ての点において、これはちょうどJavaと同じです。なぜなら、privateプロパティへデフォルトゲッターとセッターでのアクセスが、関数呼び出しのオーバヘッドが無いように最適化されているためです。
コンパイル時定数
値がコンパイル時にわかるプロパティは、 const 修飾子を使用して、 コンパイル時定数 (compile time constants) としてマークすることができます。 このようなプロパティは、次の要件を満たす必要があります:
このようなプロパティには、アノテーションを付けることができます:
遅延初期化プロパティ
通常、非null型として宣言されたプロパティは、コンストラクタ内で初期化される必要があります。 しかし、かなり多くの場合において、これは便利ではありません。 たとえば、プロパティは、依存オブジェクト (DI; dependency injection; 依存性注入, 訳注:参考)を介して、またはユニットテストのセットアップメソッドで初期化することができます。 この事例では、非nullのイニシャライザをコンストラクタ内で提供することができませんが、それでもなおクラス内の本体にあるプロパティを参照する際にnullチェックを避けたいでしょう。
このような事例を扱うには、lateinit 修飾子でプロパティをマークすると良いでしょう:
@SetUp fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method() // 参照先を直に見に行く(dereference directly)
}
}
この識別子はクラス本体(プライマリコンストラクタでない)の中で宣言され、カスタムゲッターやカスタムセッターを持たない var プロパティでのみ使用することができます。 プロパティの型が非nullかつ、プリミティブ型であってはなりません。
lateinit プロパティが初期化される前にアクセスした場合、アクセスされたプロパティと、それが初期化されていないことを特定するための特別な例外が投げられます。
プロパティのオーバライド
メンバのオーバライド を参照してください。
委任プロパティ (Delegated Properties)
プロパティのうち最も一般的なのは、単純にバッキングフィールドからの読み込み(または書き込みかもしれない)です。 一方、カスタムゲッターとセッターを使えばプロパティの振る舞いを如何様にも実装できます。 いろんなところに、プロパティの動作について、確立された共通パターンがあります。 いくつかの例を挙げます:遅延評価値、与えられたキーでのmapの読み込み、データベースへのアクセス、アクセスをトリガとするリスナへの通知等。
このような一般的な振る舞いは、委譲プロパティ (delegated properties) を使ってライブラリに実装することができます。