Kotlin 属性
Posted 陈蒙_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin 属性相关的知识,希望对你有一定的参考价值。
声明属性
Kotlin 类里面的属性,如果是可变则用 var 修饰,如果是只读类型,则用 val 修饰。比如:
class Address {
var name: String = "Holmes Sherlock"
var streed: String = "Baker"
var city: String = "London"
var state: String? = null
var zip: String = ""
}
使用属性的时候,直接引用名字即可:
fun copyAddress(address: Address): Address {
val result = Address() // 与 Java 不同,新建示例无需 new 关键字
result.name = address.name
result.street = address.street
// ...
return result
}
Getter&Setter
在 Kotlin 中,声明一个属性的完整语法是:
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
当然,初始化和 Getter 和 Setter 是可以省略的。如果属性类型可以根据上下文推断出来,也是可以省略的。比如:
var allByDefault: Int? // 编译报错,必须初始化,使用了默认 getter 和 setter 方法
var initialized = 1 // 编译 ok,有初始化,使用了默认 getter 和 setter 方法
val 类型的数据声明与 var 类型稍稍不同:
val simple: Int? // Int 类型, 默认 getter,必须在构造函数里面进行初始化
val inferredType = 1 // Int 类型,默认 getter
所以,跟 Java 不同,Kotlin 里面的属性都是默认有 Getter 和 Setter 方法的,其中 val 修饰的只读属性只有 Getter 没有 Setter。
这是 Kotlin 比 Java 简洁的一个特点,想象每次写 Java 的数据类比如 XXBean 时,是写 getter&setter 还是直接引用属性?都要纠结一会儿,现在好了,Kotlin 直接内置了。
而且,这个特点也帮助 Kotlin 实现了声明式编程。初次接触 Kotlin 时,总是很好奇如下代码是如何实现的:
aTextView.visibility = View.VISIBLE
aTextView.text = "赋值之后立即生效的文本"
感情赋值之后应该是调用了 setter 方法来实现的。
除此之外,内置的 setter 方法也为我们提供了一个 Java 无法实现的能力:监控所有的属性赋值操作。因为 Kotlin 属性的所有赋值操作都会调用对应的 setter 方法,我们就可以重写 setter 或者通过代理来实现监听。
如何重写 getter 和 setter 方法呢?比如:
val isEmpty: Boolean
get() = this.size == 0
这样,当我们每次使用 isEmpty 属性时都会调用这个自定义的 getter。
同样的,我们也可以自定义 setter:
var stringReprentation: String
get() = this.toString
set(value) {
setDataFromString(value) // 内部转换逻辑
}
注意,set() 的参数 value 只是一个约定俗称,你完全可以换成其他你喜欢的变量名。
如果我们需要更改 setter 的访问权限而且不需要更改 setter 方法体,我们可以这样:
val setterVisibility: String = "abc"
private set
val setterWithAnnotation: String = "abc"
@Inject set
看下面这段代码:
var stringReprentation: String
get() = this.toString
set(value) {
stringReprentation = value
}
执行后你会发现,这段代码会导致堆栈溢出,因为 setter 方法里面的赋值会继续调用 setter 直至堆栈溢出。该怎么解决呢?这就要说到 Backing field 了。
Backing Field
为了解决上面的问题,默认的 setter 方法应该这么写:
var stringReprentation: String
get() = this.toString
set(value) {
field = value
}
这个 field 的作用与在其绑定的属性的 setter 方法内,可以看成是属性在内存的备份。我们可以将 Backing Field 翻译成幕后字段或影子字段。
Backing 属性
我们也可以声明自己的 Backing 性质的属性,比如下面的 _table 变量:
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap()
}
return _table ?: throw AssertionError("Set to null by another thread")
}
以上是关于Kotlin 属性的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin学习之旅解决错误:kotlin.NotImplementedError: An operation is not implemented: Not yet implemented(代码片段