2.Kotlin属性和字段

2018-10-03  本文已影响0人  世界是一个圆_

1.两个关键字

Kotlin的类和接口都可以有属性,修饰属性的关键字有var(可变的)和val(不可变的)。

1.1var

对于var来说,它具有setter和getter,声明一个属性的完整语法是:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]

比如:

var stringRepresentation: String
    get() = this.toString()
    set(value) {
        setDataFromString(value) // 解析字符串并赋值给其他属性
    }

自 Kotlin 1.1 起,如果可以从 getter 推断出属性类型:

val isEmpty get() = this.size == 0  // 具有类型 Boolean
1.1.1自定义setter和getter

一般情况下,我们不需要对setter和getter进行自定义,编译器已经默认实现了它们,如果需要自定义的话如下:

class ExampleUnitTest {

    var visibal: String = "aa"
        get() = field
        set(value) {
            field = value + "cc"
        }


    @Test
    fun testMain() {

        println(visibal)//输出aa
        visibal = "bb"
        println(visibal)//输出bbcc
    }
}

其中的field称为幕后字段,它只能在setter和getter中访问,如果不通过field改变值,使用如下方式会报堆栈溢出,因为会递归调用setter

 var visibal: String = "aa"
        get() = field
        set(value) {
            visibal = "aaa"
        }
1.2val

val只有getter没有setter

2.接口中的属性

上面介绍的属性是基于类的,你也可以在接口中定义属性。在接口中声明的属性要么是抽象的,要么提供访问器的实现。在接口中声明的属性不能有幕后字段(backing field),因此接口中声明的访问器不能引用它们。

interface MyInterface {
    val prop: Int // 抽象的
    //声明了访问器
    val propertyWithImplementation: String
        get() = "foo"

    fun foo() {
        print(prop)
    }
}

class Child : MyInterface {
    override val prop: Int = 29
}

3.属性的覆盖 力求清晰显式。与 Java 不同,Kotlin 需要显式标注可覆盖的成员(我们称之为开放)以及覆盖后的成员:

open class Foo {
    open val x: Int get() { …… }
}

class Bar1 : Foo() {
    override val x: Int = ……
}

你也可以用一个 var 属性覆盖一个 val 属性,但反之则不行。这是允许的,因为一个 val 属性本质上声明了一个 getter 方法,而将其覆盖为 var 只是在子类中额外声明一个 setter 方法。

请注意,你可以在主构造函数中使用 override 关键字作为属性声明的一部分。

interface Foo {
    val count: Int
}

class Bar1(override val count: Int) : Foo

class Bar2 : Foo {
    override var count: Int = 0
}
上一篇 下一篇

猜你喜欢

热点阅读