Kotlin之Set和Get

  • Post author:
  • Post category:其他


先看下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