Kotlin笔记(六)——属性

今天开始看看Kotlin的属性,属性的内容有两大块组成,一块是今天要介绍的,另一块是代理属性,这部分留待下一篇文章介绍。


Kotlin属性的完整语法如下所示:


var/val 属性名:属性类型 = 初始值
    getter方法

    setter方法


其中var或val,属性名是必须的,var表示属性引用可变,val表示属性引用不可变,初始值一般也是必须的,除非属性是推迟初始化的,后面会有介绍。下面按照以前的惯例,通过几个例子熟悉属性的用法。从最基本的开始。

class PersonProperty1(name: String, age: Int) {
    var mName: String = name
    var mAge: Int = age
}

class PersonProperty2(var name: String, var age: Int)

class PersonProperty3(val name: String, var age: Int)

上面的例子中定义了三个类,第一个类是最常规的用法,我们定义了mName和mAge两个属性,通过构造器的参数对其进行初始化,Kotlin自动为我们生成了属性的getter和setter方法,如果我们只是访问和设置属性值,我们不需要自己实现。


第二和第三个类则是使用了我们之前在讲解构造器时使用的语法,通过为构造器的参数添加var或者val,则可将参数直接转变为属性。继续看例子

class PersonProperty4(name: String, var age: Int) {

    var mName: String = name
        get() = field.capitalize()
        set(value) {
            field = value.capitalize()
        }
}

这个例子我们自己重新实现了getter和setter方法,由于getter只有一句表达式,我们使用了比较简洁的方式,之所以重新实现getter和setter方法,是因为我们不是直接获取和设置mName属性,而是将规范化的结果进行使用。另外这个例子中我们使用了field这个变量,它是一个属性的后台域(backing field),每个属性都有一个属于自己的后台域field。


如果属性是只读的,可以像下面的例子,使用private set:

class PersonProperty5(name: String, var age: Int) {
    var mName: String = name
        private set
}

前面使用了后台域,Kotlin还有后台属性(backing property),后台属性的定义类似于Java中定义一个私有属性,然后提供属性的getter和setter方法,如下例所示:

class PersonProperty7(name: String, var age: Int) {

    private var mName: String = name
    var name: String
        get() = mName.capitalize()
        set(value) {
            mName = value.capitalize()
        }
}

mName是后台属性,而name是访问mName属性的属性,name属性有getter和setter可以访问到mName属性。看过如何重新实现自己的getter和setter方法,我给大家看一个小陷阱,看下面的类

class PersonProperty8(name: String, var age: Int) {
    var mName: String = name
        get() = mName.capitalize()
}

编译没有问题,可以运行一下看看,会发现程序崩掉了,为什么?可以和上面的PersonProperty4类做一个比较,这里的区别在于,这个类没有使用field,而是使用了mName,当我们在getter中使用mName时,又会递归调用mName的getter方法,如此就会递归调用下去,直到程序异常退出。所以,当我们重新实现自己的getter和setter时,千万注意使用field来访问当前属性的值,而不是使用属性本身。


最后看一下懒初始化,我们的属性默认要求必须初始化,这就要求我们有时候不得不把属性定义为可空类型,然后在调用时使用?和!!来处理,但是我们很可能能够保证在程序后续的步骤中对属性进行初始化,这样我们就没有必要使用可空类型了,这时候,我们需要使用lateinit关键字,如下所示:

class Tom {
    lateinit var name: String
    var age: Int = 12

    fun init() {
        name = "Tom"
    }
}

注意,age属性不可以使用latinit关键字,因为latinit关键字使用场合要求比较严格,只可以用在非空的var属性上,这个属性必须是类内部定义的,而不能够是构造器上定义的,并且属性不能够定义getter和setter方法,属性不允许是原生类型,而age是Int类型,是一个原生类型。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值