前面已经说过,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") } } }