1. 程式人生 > >Kotlin之Set和Get

Kotlin之Set和Get

先看下kotlin裡的set和get的語法

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

格式就如上所示, set和get可寫也可不寫, 不寫的話會有預設的實現, 需要注意的是val修飾的變數是沒有set方法的, 也不允許重寫set方法, 例如下面這種寫法, 會提示不允許有set方法



看一個完整的例項程式碼

package com.wbing.kotlindemo

class Student {
    var name : String = "zhang"
        // 這裡使用field而不是使用lastName, 是因為如果使用lastName會造成遞迴呼叫從而造成記憶體溢位, 因為使用lastName也會涉及到呼叫set/get的問題
        get() = field.toUpperCase()

    var no : Int = 0
        get() = field
        set(value) {
            if (value < 10) {
                field = value
            } else {
                field = -1
            }
        }

    var classTeacher : String? = "孔子"
        set(value) = if (value == null) {
            field = "孔聖人"
        } else {
            field = value
        }
        /*set(value) = if (value == null) {
            this.classTeacher = "孔聖人"
        } else {
            this.classTeacher = value
        }*/

    var isKZ : Boolean = true
        get() {
            return this.classTeacher == "孔聖人"
        }

    var className : String ? = "1班"
//        private set
}

fun main(args: Array<String>) {
    var stu: Student = Student()

    stu.name = "wang"
    println("lastName:${stu.name}")

    stu.no = 9
    println("no:${stu.no}")

    stu.no = 20
    println("no:${stu.no}")

    stu.classTeacher = null
    println(stu.classTeacher)
    println(stu.isKZ)

    stu.className = "一年一班"
    println(stu.className)
}

以上的程式碼執行結果如下:

lastName:WANG
no:9
no:-1
孔聖人
true
一年一班

對於程式碼需要說明的有幾點:

1. field的用法, field被大神們翻譯成Backing Fields(後端變數), 它的作用就類似於java裡的this.屬性名, 例如上面程式碼中的第六行get() = field.toUpperCase(), 就相當於java裡的 this.name.toUpperCase(),  但是不能直接使用this.name會造成遞迴呼叫記憶體溢位的,  因為在set和get中是不允許有本身的區域性變數的(例如如果你屬性名是name, 在set/get裡是不能有這個變數的), 因為屬性的呼叫也涉及到了set/get會造成遞迴呼叫, 所以要解決引用自身的問題, kotlin發明了field(後端變數)來解決這個問題

    注意不是set/get裡不允許有區域性變數, 是不允許有和屬性本身相同名字的區域性變數, 下面這種寫法是沒問題的

    var test : Int = 0
        get() {
            var t = 1
            field = t
            return field
        }

2. 注意程式碼中的第30~33行, 為什麼使用this.classTeacher不報錯, 是應為這個get方法是isKZ屬性的get, 而不是classTeacher的get方法

3. 如果把第36行的註釋開啟那麼main方法裡的stu.className="一年一班"會報如下錯誤

Error:(62, 5) Kotlin: Cannot assign to 'className': the setter is private in 'Student'

提示className屬性的setter是私有的不能被賦值,  通過這種方式我們可以禁止某些屬性被修改,  需要注意的是get方法不能隨便定義成private的,  需要和變數的可見範圍是一樣的, 如果變數是public的, 那麼get是不能設定成private的例如

    var className : String ? = "1班"
        private set
        private get
這個會報錯: Error:(37, 9) Kotlin: Getter visibility must be the same as property visibility