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}")
}
\