属性和字段
Kotlin官网:Classes and Objects-Properties and Fields
属性声明
类中可以声明属性。var可变,val只读。
class Student{
val name = "Tom"
var age = 12
}
使用方法和Java中的字段相同,对象.属性名
class Tom {
val name = "Tom"
var age = 12
}
fun tomGrowup(tom: Tom) {
tom.age++
println(tom.name)
println(tom.age)
}
Getter和Setter
定义属性的完整格式
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
var/val 属性名 : 属性类型 = 初始化
get() = ...
set(value) = ...
类型、初始化、访问器都是可省略的。
类型在可以被推导出时可以省略:初始化代码中推导出类型,1.1开始getter可以推导出类型。
只读属性和可变的有两个区别:1使用val声明,2不允许setter。
setter和getter可以在属性声明中自定义。
setter的参数约定俗成使用value,也可以自定义名字。
当使用访问器默认实现但需要添加修饰时,可以只写set/get关键字。
class Student {
var name = "LiLei"
var age = 12
private set //使用默认set实现,只添加访问限制
val gender:Int? = 0
var adult //省略初始化
get() = age>12
set(value){
if(value&&age<18){
age = 18
}
}
}
后备字段
类中无法直接定义字段,Kotlin自动提供后备字段。
使用field
关键字调用。
field关键字只能在访问器中使用。
filed只有被使用了才会被生成,如使用默认访问器,在自定义访问器中使用了field。
var counter = 0 // the initializer value is written directly to the backing field
set(value) {
if (value >= 0) field = value
}
//这种情况不会生成field
val isEmpty: Boolean
get() = this.size == 0
field存在的意义是解决访问器中访问属性,如果在setter中写成这样
var counter = 0 // the initializer value is written directly to the backing field
set(value) {
if (value >= 0) counter = value
}
写成属性=值
实际上是在setter中调用了setter赋值,循环调用,相当于Java中
void set(int value){
if(value>=0) set(value);
}
会出现栈溢出错误。field就相当于”属性的this”。
后备属性
后备字段不满足需求时可以使用后备属性
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
}
return _table ?: throw AssertionError("Set to null by another thread")
}
编译期常量
在编译期值确定的属性可以定义为编译期常量。
使用const
关键字定义。
必须满足下面的要求:
* 顶级元素;对象的成员
* 字符串;基本类型
* 没有自定义getter
编译期常量可以在注解中使用
const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
@Deprecated(SUBSYSTEM_DEPRECATED) fun foo() { ... }
延迟初始化的属性和变量
某些情况下属性不能立刻初始化,如注入的对象,单元测试等,可以修为延迟初始化。
关键字lateinit,可修饰类体中的var属性。不能在主构造函数中,属性不能有自定义访问器。
1.2之后顶级属性和局部变量必须是非空且不能为基本类型。
在延迟初始化的属性被初始化之前访问会抛出UninitializedPropertyAccessException异常。
延迟初始化变量的初始化检查(1.2后支持)
使用isInitialized判断。
if (foo::bar.isInitialized) {
println(foo.bar)
}
属性重写
见3-1属性重写
属性代理
见3-13属性代理