KotlinDive

プログラミング言語 Kotlin についての入門ブログです。

クラス(プロパティ)

プロパティの宣言

クラスのボディに「val」キーワードで宣言すると読取り専用で、 「var」キーワードで宣言すると変数としてプロパティを宣言できます。
プロパティは必ず初期化しないといけません。初期化は「プロパティイニシャライザ」か「イニシャライザブロック」で行います。


fun main(args: Array) {
    val suzuki = Student("suzuki", 80.0)

    // nameは読取り専用なので変更できない
    // 下記のコードはビルドエラー
    // suzuki.name = "tanaka"
    suzuki.score = 70.0

    println("name = ${suzuki.name}")
    println("score = ${suzuki.score}")
    println("note = ${suzuki.note}")
}

class Student(name: String, score: Double) {
    val name = name
    var score = score

    // プロパティは必ず初期化しないといけない
    // 次のコードはビルドエラーになる
    // val desc: String

    var note: String

    init {
        // イニシャライザブロックで初期化してもOK
        note = "None"
    }
}

name = suzuki
score = 70.0
note = None

ゲッター/セッター

プロパティはゲッター/セッターを持ちます。
上記の例でもインスタンス「suzuki」からプロパティ「score」に値をセットしています。 直接値をセットしているように見えますが、実際にはデフォルトセッターを通じて値がセットされている状態です。 値を取得している部分も、デフォルトゲッターを通じで値を取得しています。
カスタムゲッター/セッターを作成するには「get」「set」を利用します。
カスタムゲッター/セッター内で、そのプロパティ自身にアクセスするには「field」を利用します。 これを「バッキングフィールド」といいます。 (カスタムゲッター/セッターで、自分自身にアクセスするのに自分のプロパティ名を利用すると、 無限にゲッター/セッターを呼び出すことになりスタックオーバーフローになります。 例えば、nameゲッター内でreturn nameとすると再びnameゲッターを呼ぶことになります。 するとnameゲッターでnameゲッターを呼び、またそのnameゲッターでnameゲッターを呼び... と無限に呼び出してしまします)


fun main(args: Array) {
    val suzuki = Student("suzuki", 80.0)

    suzuki.score = 70.0
    suzuki.score = -10.0

    println("name = ${suzuki.name}")
    println("score = ${suzuki.score}")
    println("note = ${suzuki.note}")
}

class Student(name: String, score: Double) {
    val name = name
        get() = field.toUpperCase()
        // nameは読取り専用なので、setterを作成することはできない

    var score = score
        get() = field / 100.0
        set(value) {
            if (value < 0.0 || 100.0 < value) {
                return
            }

            field = value
        }

    var note: String

    init {
        note = "None"
    }
}

name = SUZUKI
score = 0.7
note = None

また、必要に応じてゲッター/セッターにもヴィジビリティ修飾子やアノテーションを指定することができます.


fun main(args: Array) {
    val suzuki = Student("suzuki", 80.0)

    // scoreセッターはprivateなので、以下はビルドエラーになる
    // suzuki.score = 70.0
    // suzuki.score = -10.0

    println("name = ${suzuki.name}")
    println("score = ${suzuki.score}")
    println("note = ${suzuki.note}")
}

class Student(name: String, score: Double) {
    val name = name
        get() = field.toUpperCase()

    var score = score
        get() = field / 100.0
        private set(value) {
            if (value < 0.0 || 100.0 < value) {
                return
            }

            field = value
        }

    var note: String

    init {
        note = "None"
    }
}

name = SUZUKI
score = 0.8
note = None