Kotlin学习笔记之属性

886 阅读2分钟

kotlin中的属性既可以用var声明为可变的,也可以用val声明为不可变的,即只读的。

只读属性的语法和可变属性的语法有两方面的不同

  • 只读属性用val关键字修饰。
  • 只读属性不允许有setter函数

声明属性的完整语法为:

  • 可变属性

    var <propertyName>[: <PropertyType>] [= <property_initializer>]
        [<getter>]
        [<setter>]
    
  • 只读属性

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

我们可以为属性定义自定义的访问器,可以自定义getter或者setter。

var age:String
get() {
    return age + "岁"
}
set(value) {
    // 此处可进行一些校验或者数据格式化的操作  2021/6/21
    age = value
}
在Kotlin中访问一个属性的实质是访问了这个属性的getter方法。赋值一个属性或者说写一个属性的实质是访问了这个属性的setter方法。

幕后字段

在自定义setter方法中使用age = value时会出现Exception in thread "main" java.lang.StackOverflowError 异常,是因为此时的属性复制发生了循环调用,正确的使用方法应该是使用幕后字段field,即在setter中为属性赋值时,其实是为属性的幕后字段field赋值:

var age:String
get() {
    return age + "岁"
}
set(value) {
    // 此处可进行一些校验或者数据格式化的操作  2021/6/21
    field = value
}

幕后字段的应用举例:

var age:String
get() {
    return age + "岁"
}
set(value) {
    // 此处可进行一些校验或者数据格式化的操作  2021/6/21
    if(value > 0){
        field = value
    }else{
        field = 0
    }
}

field标识符只能用在属性的访问器内,如果属性至少有一个访问器使用了默认实现,或者自定义的访问器引入了幕后字段,将会为属性生成一个幕后字段。

比如下面的情况就没有幕后字段

val isEmpty: Boolean
    get() = this.size == 0

因为val修饰的属性只有get访问器,且在get访问其中没有使用filed幕后字段。

属性的延迟初始化

  • 用关键字lateinit修饰属性,可以延迟初始化该属性。
  • 可以用属性引用的isInitialized来判断延迟初始化的属性是否被初始化。
    lateinit var address:String
    
    fun varMethod(){
        if(::address.isInitialized){
            println("属性address已被初始化")
            println("address = ${address}")
        }else{
            println("属性address未被初始化")
            address = "这是地址"
        }
        println(::address.isInitialized)
        println("address = ${address}")
    }

\