※本サイトで紹介している商品・サービス等の外部リンクには、アフィリエイト広告が含まれる場合があります。

10-2. プロパティとアクセサ (setter/getter)

2023年9月23日

概要

Kotlin では、プロパティを定義するだけで自動的にそのプロパティ変数の値を設定したり、値を参照するための関数 (アクセサ Accessor) が自動的に作成されます。
自分でアクセサを定義することも可能です。

プロパティに値を設定するアクセサを セッター (setter)、値を参照するアクセサをゲッター(getter) と呼びます。

プロパティとバッキングフィールド

定義されたプロパティには、自動的にバッキングフィールド (baking field) が生成されます。
バッキングフィールドは、 プロパティの値を格納するためのメモリ領域を提供します。
プロパティにはこのバッキングフィールドへの参照が保持されます。
バッキングフィールドへのアクセスが可能なのはプロパティのみです。

カスタムアクセサを使用するときに、このバッキングフィールドにアクセスするには field という識別子 (予約語、キーワード) を使います。

プロパティの書式

プロパティのフルの書式は以下です。

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]

mutable(可変) な var ではなく、immutable(不可変) な val でも定義可能です。

ここで initializer と getter, setter の記載は必須ではありません。

デフォルトで用意される getter と setter

getter と setter を記載しない場合はデフォルトで用意されます。(見えません。)

ここでは、デフォルトで用意される getter と setter と同じものを自分で定義した例を記載します。

fun main(){
    val myPersonObj : Person = Person()
    myPersonObj.name = "HogeHoge"
    myPersonObj.age = 3
    myPersonObj.greeting()
}

class Person {
    var name : String = ""
        get() {
            return field
        }
        set(value) {
            field = value
        }
    var age : Int = 0
        get() {
            return field
        }
        set(value) {
            field = value
        }
    fun greeting(){
        println("Hello World!\r\n私は ${name} です。年齢は ${age} 才です。")
    }
}

ここで、先ほど記載したようにバッキングフィールドへのアクセスのため field という識別子が使われています。
これによりプロパティの値が保持されるバッキングフィールドとのやりとり (値を設定する、値を参照する) を行います。

get() で getter 、set() で setter を定義する形となります。
set() にはパラメータが必要となります。パラメータ名は任意にできます。一般的には value とすることが多いようです。
getter では field の値の参照、setter では field の値への代入という形となっています。

この出力は 10-1. で記載したのと同じになります。

実行結果)

Hello World! 私は HogeHoge です。年齢は 3 才です。

カスタムアクセサの例

単にバッキングフィールドの値を参照したり設定するだけではなく処理を行わせたい場合など、デフォルトのゲッターやセッターでは不十分な場合、 カスタムアクセサを定義することができます。

以下の例は、セッターで値を設定する前に、何の値が設定されようとしているのかを println で表示されるように変えています。
これだけではあまり意味はありませんが、この処理をするための分岐やフラグなどを工夫すればある種のデバッグの際に使うことができると思います。

fun main(){
    val myPersonObj : Person = Person()
    myPersonObj.name = "HogeHoge"
    myPersonObj.age = 3
    myPersonObj.greeting()
}

class Person {
    var name : String = ""
        get () {
            println("名前を取得しています。")
            return field
        }
        set(value) {
            println("name に ${value} が設定されます。")
            field = value
        }
    var age : Int = 0
        get() {
            println("年齢を取得しています。")
            return field
        }
        set(value) {
            println("age に ${value} が設定されます。")
            field = value
        }
    fun greeting(){
        println("Hello World!\r\n私は ${name} です。年齢は ${age} 才です。")
    }
}

実行結果)

name に HogeHoge が設定されます。
age に 3 が設定されます。
名前を取得しています。
年齢を取得しています。
Hello World!
私は HogeHoge です。年齢は 3 才です。