对于 Kotlin 中的属性,有两种方式声明:
二者区别没啥好说的,var
声明属性后期可以赋值,而 val
声明的属性,初始化赋值之后,不能再赋值了,类似于 Java 中的 final 属性。
在 Kotlin 中,var 类型的属性是自带 getter 和 setter 方法,val 自带 getter 方法(因为它后期不能修改嘛),我们直接通过对象调用该属性,实际上是调用了它的 getter 或 setter 方法:
fun main() {
var person = Person("张三", 20)
person.age = 10 //实际调用了 age 属性的 setter 方法
person.name = "李四" //这句会报错,因为 name 属性是 val 类型的
}
class Person(name: String, age: Int) {
val name: String = name
var age: Int = age
}
当然,我们也可以自定义他们的 setter 和 getter 方法:
fun main() {
var person = Person("张三", 20)
person.name = "李四"
person.age = 20
print(
"${person.name} ${person.age}"
)
}
class Person(name: String, age: Int) {
var name: String = name
get() {
return "$field$field"
}
var age: Int = age
set(value) {
if (value > 18) {
field = 18
} else {
field = value
}
}
}
//输出结果是:李四李四 18
在文档中,关于幕后字段的解释有点儿说的云里雾里,我是这么理解的:
首先咱们写 Java 时经常这么写:
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
先声明一个字段 name,然后可以通过它的 setter 和 getter 方法来操作它,但是如果在 Kotlin 中也按照这个思路来写它的 setter 和 getter 方法,就会有问题:
fun main() {
var person = Person("张三")
person.name = "李四"
print(
"${person.name} "
)
}
class Person(name: String) {
var name: String = name
set(value) {
name = "$value$value"
}
}
在 Kotlin 中,提供了一个 field
,我们 get 和 set 方法的操作,实际上是对这个 field 的操作,我们这样修改一下就没问题了:
class Person(name: String) {
var name: String = name
set(value) {
field = "$value$value"
}
}
为什么需要这么做呢,我刚开是也是觉得蛋疼,查了一圈,各种文章也是抄官方文档,照样云里雾里,最后看到一个靠谱的通俗易懂的解释:
当我们在外部使用 对象.属性
来操作属性的时候,实际上,是调用了属性的 set 或者 get 方法,那再看之前错误的写法:person.name = "李四"
翻译过来就是 person.setName
,而在 set 方法内部,再调用 name = "$value$value"
,岂不是在 set 方法中调用 set 方法,无出口递归嘛。而 field 就相当于给你提供了一个隐藏的私有变量。