プロパティ

Properties

プロパティの宣言

varキーワードは、変更可能。valキーワードは、読み取り専用となる。

class Address {
    var name: String = "Holmes, Sherlock"
    var street: String = "Baker"
    var city: String = "London"
    var state: String? = null
    var zip: String = "123456"
}

プロパティを使うには、その名前を通してかんたんに参照する。

fun copyAddress(address: Address): Address {
    val result = Address()
    result.name = address.name
    ....
    return result
}

GetterとSetter

プロパティのフルシンタックスは以下になる。

var プロパティ名[: 型] [= 初期化]
    [get()]
    [set(value)]

get()を使うことで、Computed property(計算プロパティ)を宣言することができる

val isEmpty: Boolean
    get() = this.size == 0

setter

var stringRepresentation: String
    get() = this.toString()
    set(value) {
        field = value
    }

プロパティの型は、getterから推測できる場合は、省略できる。

val isEmpty get() = this.size == 0

アクセス権(visibility)の変更もしくは、それに対するアノテートをする必要があるが、デフォルトの実装に変更は必要としない場合、その本体を宣言することなくアクセッサーを定義することができる。

// setterをprivateに変更する
var setterVisibility: String = "abc"
    private set

// setterにアノテートをつける
var setterWithAnnotation:Any? = null
    @Inject set

Backing fields

Kotlinでは、フィールドは値を保持するためのプロパティの一部としてのみ使用される。 フィールドを直接宣言することはできない。

しかしながら、プロパティは背後のフィールドを必要とすることがある。 Kotlinは自動的にそれを提供する。

この背後のフィールドはfield識別子を使ってアクセッサー内部で参照することができる。

var counter = 0  // 初期化は、背後のフィールドに直接値を代入する
    set(value) {
        if (value % 2 == 0) field = value
        else filed = value + 1
    }

Backing properties

暗黙のbacking fieldを使いたくない場合は、backing propertyを使って同じことができる。

// backing property
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
    get() {
        if (_table == null) {
            _table = HashMap()
        }
        return _table ?: throw AssertionError("Set to null by another thread")
    }

コンパイル時定数

const修飾子を使うことによって、コンパイル時の定数であることをマークすることができる。 ただし以下の条件がある。

  • トップレベルもしくは、object宣言のメンバ もしくは、companion object
  • Stringもしくは基本型による初期化
  • getterを持たない
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"

// 定数は、アノテーションで使用することができる
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { ... }

遅延初期化プロパティと変数

lateinit修飾子をつけることで、遅延初期化することができる。

public class MyTest {
    // lateinitをつけると初期化コードが不要となる
    lateinit var subject: TestSubject

    @SetUp fun setup() {
        subject = TestSubject()
    }
}

初期化済みかどうかは、.isInitializedを使う

if (foo::bar.isInitialized) {
    println(foo.bar)
}