Menu
CoddyTech

自定义访问器

本课属于 Coddy Kotlin 学习旅程的“面向对象编程”单元。第 7 课,共 57 课。

每个 Kotlin 属性都有一个getter(获取器),每个 var 也都有一个setter(设置器)。默认情况下,它们会读取和写入存储的值。自定义 getter 会在每次读取时计算值:

class Rectangle(var width: Int, var height: Int) {
    val area: Int
        get() = width * height
}

在 main 中:

val r = Rectangle(3, 4)
println(r.area)
r.width = 10
println(r.area)

输出:

12
40

每当属性被赋值时,自定义 setter 都会运行代码。在其中,value 是赋给属性的值,field 是属性背后存储的值,也就是后备字段:

class Thermostat {
    var target = 20
        set(value) {
            field = value.coerceIn(10, 30)
        }
}

在 main 中:

val t = Thermostat()
t.target = 42
println(t.target)
t.target = 18
println(t.target)

输出:

30
18

在访问器中,使用 field,而不是属性名:在 target 的 setter 中写 target = value 会再次调用 setter,造成无限递归:

var target = 20
    set(value) {
        // target = value        // 会再次调用这个 setter:导致无限递归
        field = value             // 存储这个值
    }

setter 也是响应更改的地方,例如可以统计或记录更改:

class Player(name: String) {
    var changes = 0
        private set
    var name = name
        set(value) {
            field = value.trim()
            changes++
        }
}

在 main 中:

val p = Player("ada")
p.name = "  Ada  "
p.name = "Ada L."
println("${p.name} after ${p.changes} changes")

输出:

Ada L. after 2 changes
challenge icon

挑战

简单

完成类 Circle(radius: Double)。radius 是一个 var,其 setter 会将负值存储为 0。添加只读属性 diameter 和 area(π r²,使用 Math.PI),并添加 label,它会返回 r=2.0 d=4.0 a=12.57,其中面积四舍五入到小数点后两位("%.2f".format(area))。

提供的代码会逐行读取一个半径,打印 label,然后将最后一个圆的半径加倍,再次打印 label,因此这些值必须随半径变化。

你的代码写在 Circle.kt 中。Main.kt 中包含提供的输入/输出代码,不能编辑。

亲手试试

fun main() {
    // 提供的输入/输出代码:保持原样
    val input = generateSequence(::readLine).toList()
    var last = Circle(0.0)
    for (line in input) {
        last = Circle(line.toDouble())
        println(last.label)
    }
    last.radius *= 2
    println(last.label)
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Kotlin 在线编辑器