声明
与java不同,kotlin类中的属性可以生命可变和只读的关键字
var 声明为可变的
val 声明为只读的
类似java可以通过引用来使用属性
定义类
internal class PropertyInfo {
var id : Int = 0
var name: String = "name"
var purpose :String = "purpose"
fun printInfo(){
println("id: $id name: $name purpose: $purpose")
}
}
对象属性的使用
fun main(args: Array<String>){
var propertyInfo = PropertyInfo()
propertyInfo.id = 2;
propertyInfo.name = "property name"
propertyInfo.purpose = "property purpose"
propertyInfo.printInfo()
}
结果
id: 2 name: property name purpose: property purpose
Getters 与 Setters
声明一个属性的完整语法是
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
这个看起来比较专业生硬,可以参考如下更接地气的示例
var setStr : String = ""
get() = field
// 设置属性值时,先执行(field相关)
set(value) {
if (field.equals("")){
field = "empty"
}else {
field = value
}
}
需要注意的是:初始器(initializer)、getter 和 setter 都是可选的。属性类型如果可以从初始器 (或者从其 getter 返回值,如下文所示)中推断出来,也可以省略。
属性类型可以省略的,那上面的示例来讲,也就是:String 类型可以省略,因为可以从初始器可以推断出来。如:
var allByDefault: Int? // 错误:需要显式初始化器,隐含默认 getter 和 setter
var initialized = 1 // 类型 Int、默认 getter 和 setter
这里所说的getter和setter和java里常见定义的getter,setter实际功能是一样的,但是调法不一样。kotlin中不能显示调用,直接使用属性就附带getter和setter功能。
fun main(args: Array<String>){
setStr = "";
println("str isEmpty $setStr")
}
运行发现setStr已经修改为了“empty”而不是“”
str isEmpty empty
幕后字段
在Kotlin中,字段仅在需要时作为属性的一部分使用,以便在内存中保存其值。字段不能直接声明。然而,当一个属性需要一个幕后字段时,Kotlin 会自动提供。这个幕后字段可以使用field
标识符在访问器中引用:
var setStr : String = ""
get() = field
// 设置属性值时,先执行(field相关)
set(value) {
if (field.equals("")){
field = "empty"
}else {
field = value
}
}
上文中提到的field 标识符只能用在属性的访问器内。
如果属性至少一个访问器使用默认实现,或者自定义访问器通过 field
引用幕后字段,将会为该属性生成一个幕后字段。
对应的有幕后属性
幕后属性
幕后属性是我们自己定义的,一般用于这种情况:
- 我们希望定义一个这样的变量
- 对外表现为只能读,不能写
- 对内表现可以任意读写
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 - 专项 - 幕后字段、幕后属性-CSDN博客,介绍的很详细
编译期常量
如果只读属性的值在编译期是已知的,那么可以使用 const 修饰符将其标记为编译期常量。 这种属性需要满足以下要求:
- 位于顶层或者是 object 声明 或 companion object 的一个成员
- 以
String
或原生类型值初始化 - 没有自定义 getter
延迟初始化属性与变量
一般地,属性声明为非空类型必须在构造函数中初始化,如果有些不需要立马初始化的场景就不方便,用代码来看
var str:String //不初始化会报错
lateinit var latStr :String //可能会导致忽略初始化问题
val lazyStr : String by lazy { "1" } //推荐使用,第一次调用初始化
总结
比较特殊的有
getter,setter访问器
幕后字段和属性
延迟初始化