前面已经说过,Kotlin 的属性可以使用 val 或者 var 关键字标识的,val 声明属性是不可变的,只能读,而 var 是可变的,允许读和改变。而且在 Kotlin 中调用属性只需要向 Java 中的一样,使用实例调用即可:
class Demo{
val isAlive = true
var name:String = ""
var age:Int = 0
var sex:String=""
}
fun createDemo(mDemo: Demo):Demo{
val demo = Demo()
mDemo.name = demo.name
mDemo.age = demo.age
mDemo.sex = demo.sex
return demo
}
属性的完整写法(括号里面的可以省略):
var name(:Type)(?)(=init)
(getter)
(setter)
// 类似于下面这个
var name:String?="hhhh"
当然,val 的属性只要可读性,是没有 setter 的,属性的 setter 和 getter 方法主要是用于对自身的改变,类似于拦截器,就是当你读数据或者是写数据时,它都会执行 getter 或者 setter 方法,比如下面这种写法:
class Demo{
var name:String=""
set(value) {
field = "${value[0]}先生"
}
}
fun main(args: Array<String>) {
val demo = Demo()
demo.name = "宋琪飞"
println(demo.name)
}
结果:
gettter 和 setter 都是对属性自身的处理,而 Kotlin 类中不能直接声明一个字段再来说明这个属性,这个时候就提供了一个 filed 关键字来引用这个字段(这个字段就是幕后字段),filed 只能在属性的访问器内使用,如果属性至少一个访问器使用默认实现,或者自定义访问器通过 filed 引用幕后字段,将会为该属性生成一个幕后字段。
除了幕后字段,还有幕后属性,如果你想要的效果不太适用幕后字段,就可以使用幕后属性:
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")
}
编译期常量:当熟悉需要满足位于顶层或者是 Object 的一个成员、使用原生类型初始化、没有自定义的 getter 时,可以使用 const 关键字标记为编译期常量。这些属性可以用在注解中:
const val MESSAGE:String = "MESSAGE"
@Deprecated(MESSAGE) fun answer(){}
当属性通过依赖注入或者 SetUp 方法中初始化时,我们可以使用 lateinit 关键字标记属性,来延迟初始化属性和变量,在类体中引用属性时避免空检查:
lateinit var name:String
在初始化前访问一个 lateinit 属性会抛出一个特定异常,该异常明确标识该属性被访问及它没有初始化的事实。如果要检测一个 lateinit 的属性有没有被初始化,可以在该属性的引用上使用 .isInitialized
class Demo{
}
class Test{
lateinit var demo: Demo
fun answer(){
if (Test::demo.isLateinit){
println("YES")
}
}
}