声明一个属性的完整语法是
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
幕后字段
在 Kotlin 类中不能直接声明字段。
class Person {
//错误的演示
var name = ""
set(value) {
this.name = value
}
}
如果属性至少一个访问器使用默认实现,那么Kotlin会自动提供幕后字段,用关键字field表示,幕后字段主要用于自定义getter和setter中,并且只能在getter和setter中访问。
var counter = 0 // 注意:这个初始器直接为幕后字段赋值
set(value) {
if (value >= 0) field = value
}
field 标识符只能用在属性的访问器内。
幕后属性
如果你的需求不符合这套“隐式的幕后字段”方案,那么总可以使用 幕后属性(backing property): 我们希望一个属性:对外表现为只读,对内表现为可读可写,我们将这个属性成为幕后属性
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")
}
将_table属性声明为private,因此外部是不能访问的,内部可以访问,外部访问通过table属性,而table属性的值取决于_table,这里_table就是幕后属性。
延迟初始化属性与变量
一般地,属性声明为非空类型必须在构造函数中初始化 ,如果想做延时初始化 可以用 lateinit 修饰符标记该属性:(然而,这经常不方便。例如:属性可以通过依赖注入来初始化, 或者在单元测试的 setup 方法中初始化)
public class MyTest {
lateinit var subject: TestSubject
}
要检测一个 lateinit var 是否已经初始化过,在该属性的引用上使用 .isInitialized:
if (foo::bar.isInitialized) {
println(foo.bar)
}
此检测仅对可词法级访问的属性可用,即声明位于同一个类型内、位于其中一个外围类型中或者位于相同文件的顶层的属性。