Kotlin - クラス - プロパティ

公開日:2019-11-21 更新日:2019-11-23
[Kotlin]

1. 概要

プロパティについてです。


2. プロパティ

クラスで保持する値は、全てプロパティとして扱います。
Kotlin では、インスタンス変数(インスタンスフィールド)を定義できません。
インスタンス変数に見える変数は、アクセサー(setter や getter)が省略されたプロパティになります。
プロパティの実際の値は裏で保持しており、field(バッキングフィールド )を使って、代入・取得が行えます。

class Test {
    var value1:Int = 0  // プロパティ
}

fun main() {
    val obj = Test()
    obj.value1 = 100
    println(obj.value1)  // 100
}

単純なプロパティは、コンストラクタで var または val を付けるだけで定義できます。
コンストラクタの引数をコンストラクタでのみ使用する場合は、var または val をはずしてください。
class Test(val no:Int, var name:String)

fun main() {
    val obj = Test(1, "apple")
    println(obj.no)    // 1
    println(obj.name)  // apple
}


3. アクセサー

プロパティの直後の get() と set() がプロパティに対応するアクセサーになります。
set の引数には、プロパティへ代入した値が入ります。
プロパティの実際の値は、field を使って、代入・取得が行えます。

class Test {
    var value1:Int = 0
        get() = field
        set(v) { field = v }

    var value2:Int = 0
        get() {
            return field
        }
        set(value) { field = value }
}

fun main() {
    val obj = Test()
    obj.value1 = 100
    obj.value2 = 200
    println(obj.value1)  // 100
    println(obj.value2)  // 200
}

他の言語と同様に、インスタンス変数を使ったように書くこともできますが、_value1 は field で参照できるため、冗長です。
    private var _value1:Int = 0
    
    var value1:Int
        get() = _value1
        set(value) { _value1 = value }

setter を隠蔽したい場合は、private を付けて set() を定義する必要があります。
setter を省略しただけだと、隠蔽されません。
また、プロパティを val にすることで、外部からの設定を禁止にできますが、クラス内部からも設定できなくなりますので、状況によって使い分けてください。
class Test {
    var value1:Int = 0
        get() = field
        // private set(value) { field = value }
}

fun main() {
    val obj = Test()
    obj.value1 = 100
    println(obj.value1)  // 100
}


4. インデクサ

インデクサは get() と set() に対応しています。
get() と set() をオーバーライドすることによって、
オブジェクトに対してインデクサでアクセスできるようになります。

class Test {
    private var testData:MutableMap<String, String> = mutableMapOf()

    operator fun get(key:String):String {
        return testData[key] ?: ""
    }
    operator fun set(key:String, value:String) {
        testData[key] = value
    }
}

fun main() {
    val obj = Test()
    obj["key1"] = "abc"
    println(obj["key1"]) // abc
}


5. 注意事項

Kotlin のプログラムは、JVM用のバイトコードに変換されます。
プロパティは get○○ や set○○ と言うメソッドに変換されるため、
get○○ や set○○ を独自に実装してしまうと、重複してコンパイルエラーになります。
class Test {
    var value:Int = 0      // 裏で getValue() と setValue() が作られる
    fun getValue():Int = 0 // 重複するためエラー
}

エラー内容
Platform declaration clash: The following declarations have the same JVM signature (getvalue()I):