原创

Kotlin的属性和字段

Kotlin的属性相当于Java的字段再加上getter和setter方法。

一、读写属性和只读属性

Kotlin使用val定义只读属性,使用var定义读写属性,系统会为只读属性生成getter方法,会为读写属性生成getter和setter方法。

Kotlin定义普通属性时,需要显式指定初始值:要么在定义时指定初始值,要么在构造器中指定初始值。

class Address {
    var street: String = ""
    var city = ""
    var province = ""
    var postCode: String? = null
}

在定义属性时,如果系统可根据属性初识值推断出属性的类型,就可以不显式指定属性的类型。

Kotlin定义一个属性,就相当于定义一个Java类的private修饰的field,以及public、final修饰的getter和setter方法。

在Kotlin类中定义属性后,被Kotlin程序使用时只能使用点语法访问属性;被Java程序使用时只能通过getter、setter方法访问属性。

  1. 只读属性用val定义,读写属性用var定义;
  2. 只读属性不允许有setter方法。

二、自定义getter和setter

在定义属性时可指定自定义的getter和setter方法。

定义getter、setter方法时无须使用fun关键字。

fun main(args: Array<String>) {
    var user = User("亮", "诸葛")
    println(user.fullName)
}

class User(first: String, last: String) {
    var first: String = first
    var last: String = last
    val fullName: String
        //自定义getter方法
        get() {
            println("执行fullName的getter方法")
            return "${first}.${last}"
        }
}

输出结果:

执行fullName的getter方法
亮.诸葛

对于只读属性来说,只能重写getter方法;对于读写属性来说,可根据需要重写其中之一,也可同时重写它们。

fun main(args: Array<String>) {
    var user = User("亮", "诸葛")
    println(user.fullName)
    user.fullName = "懿.司马"
    println(user.first)
    println(user.last)
}

class User(first: String, last: String) {
    var first: String = first
    var last: String = last
    var fullName: String
        //自定义getter方法
        get() = "${first}.${last}"
        set(value) {
            println("执行fullName的setter方法")
            if ("." !in value || value.indexOf(".") != value.lastIndexOf(".")) {
                println("输入的fullName不合法")
            } else {
                var tokens = value.split(".")
                first = tokens[0]
                last = tokens[1]
            }
        }
}

输出结果:

亮.诸葛
执行fullName的setter方法
懿
司马

三、幕后字段

如果Kotlin类的属性有幕后字段,则Kotlin要求该属性显式指定初始值。

满足以下条件,系统就会为属性生成幕后字段:

  • 该属性使用Kotlin自动生成的getter和setter方法或其中之一。
  • 重写getter、setter方法时,使用field关键字显式引用了幕后字段。
fun main(args: Array<String>) {
    var p = Person("悟空", 29)
    p.age = 120
    println(p.age)
    p.age = 25
    println(p.age)
}

class Person(name: String, age: Int) {
    var name = name
        set(newName) {
            if (newName.length > 6 || newName.length < 2) {
                println("您设置的人名不符合要求")
            } else {
                field = newName
            }
        }

    var age = age
        set(newAge) {
            if (newAge > 100 || newAge < 0) {
                println("您设置的年龄不合法")
            } else {
                field = newAge
            }
        }
}

输出结果:

您设置的年龄不合法
29
25

四、幕后属性

幕后属性就是用private修饰的属性,Kotlin不会为幕后属性生成任何getter、setter方法。

fun main(args: Array<String>) {
    var p = Person("悟空", 29)
    println(p.name)
    p.name = "八戒"
    println(p.name)
}

class Person(name: String, age: Int) {
    private var _name = name
    var name
        get() = _name
        set(newName) {
            if (newName.length > 6 || newName.length < 2) {
                println("您设置的人名不符合要求")
            } else {
                _name = newName
            }
        }
}

输出结果:

悟空
八戒

五、延迟初始化属性

Kotlin提供了lateinit修饰符来解决属性的延迟初始化。使用lateinit修饰的属性,可以在定义该属性时和在构造器中都不指定初始值。

lateinit修饰符有如下限制:

  • lateinit只能修饰在类体中声明的可变属性。
  • lateinit修饰的属性不能有自定义的getter或setter方法。
  • lateinit修饰的属性必须是非空类型。
  • lateinit修饰的属性不能是原生类型。

如果在lateinit属性赋初始值之前访问它,程序将会引发“lateinit property name has not been initialized”异常。

六、内联属性

inline修饰符可修饰没有幕后字段的属性的getter或setter方法,既可单独修饰属性的getter或setter方法;也可修饰属性本身,相当于同时修饰该属性的getter和setter方法。

fun main(args: Array<String>) {
    var product = Product()
    var name=product.author.name
    println(name)
}

class Name(name: String, desc: String) {
    var name = name
    var desc = desc
}

class Product {
    var productor: String? = null
    //inline修饰属性的getter方法,表明读取属性时会内联化
    val proName: Name
        inline get() = Name("Python", "当前热推语言")
    //inline修饰属性的setter方法,表明设置属性时会内联化
    var author: Name
        get() = Name("龟书", "一个大神")
        inline set(v) {
            this.productor = v.name
        }
    //inline修饰属性本身,表明读取和设置属性时都会内联化
    inline var pubHouse: Name
        get() = Name("开源社区", "无")
        set(v) {
            this.productor = v.name
        }
}

输出结果:

龟书

学海无涯苦作舟

我的微信公众号.jpg

基本语法
  • 作者:HunterArley (联系作者)
  • 发表时间:2019-11-26 09:50
  • 版权声明:本网站部分内容转载于合作站点或其他站点,但都会注明作/译者和原出处。如有不妥之处,敬请指出。
  • 公众号转载:请在文末添加作者公众号二维码