Menu
CoddyTech

super 与构造函数

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

super.method() 会在重写的方法内部调用超类版本的方法。子类可以扩展继承的行为,而不是将其替换:

open class Notification(val text: String) {
    open fun render() = "[info] $text"
}
class Reminder(text: String, val minutes: Int) : Notification(text) {
    override fun render() = super.render() + " (in $minutes min)"
}

在 main 内:

println(Notification("backup done").render())
println(Reminder("meeting", 10).render())

输出:

[info] backup done
[info] meeting (in 10 min)

每个子类都必须调用超类构造函数。使用主构造函数时,调用写在类头中,格式为 : Base(arguments),参数可以根据子类的参数计算得出:

open class Product(val name: String, val price: Int)

class Discounted(name: String, price: Int, val percent: Int) :
    Product(name, price * (100 - percent) / 100)

在 main 中:

val tea = Discounted("tea", 500, 10)
println("${tea.name} ${tea.price} (${tea.percent}% off)")

输出:

tea 450 (10% off)

创建过程从继承层次结构的顶层向下进行:先运行超类的属性初始化器和 init 块,然后运行子类的:

open class Base(name: String) {
    init { println("Base init for $name") }
}
class Child(name: String) : Base(name.uppercase()) {
    init { println("Child init for $name") }
}

在 main 中:

Child("kit")

输出:

Base init for KIT
Child init for kit

没有主构造函数的类会在每个次构造函数中使用 super(...) 调用超类,或者使用 this(...) 委托给自己的另一个构造函数:

open class Shape(val name: String)

class Rect : Shape {
    val w: Int
    val h: Int

    constructor(w: Int, h: Int) : super("rect") {
        this.w = w
        this.h = h
    }

    constructor(side: Int) : this(side, side)
}

在 main 中:

val r = Rect(3)
println("${r.name} ${r.w}x${r.h}")

输出:

rect 3x3

由于超类会先完成设置,因此它不应该在构造函数或 init 中调用 open 成员。子类自己的属性还没有值时,重写的方法就会运行:

open class Base {
    init { println("Base sees: ${describe()}") }
    open fun describe() = "base"
}
class Child : Base() {
    val label = "child"
    override fun describe() = "label is $label"
}

在 main 中:

Child()

输出:

Base sees: label is null
challenge icon

挑战

简单

Notification(text) 有一个 open 方法 render(),它会返回 [info] text。请完成这些子类:Warning 的 render() 会返回大写文本组成的 [warn] TEXT;Reminder 还会保存 minutes,并使用 super 返回超类的结果,后面接上 (in 10 min)。

提供的代码会读取 info,text、warn,text 或 remind,text,10 这样的行,在一个 List<Notification> 中创建对应的对象,并打印每个对象的 render()。

你的代码应写在 Notification.kt、Warning.kt 和 Reminder.kt 中。Main.kt 包含提供的输入和输出代码,不能编辑。

亲手试试

fun main() {
    // 提供的输入/输出代码:保持原样
    val input = generateSequence(::readLine).toList()
    val notes = mutableListOf<Notification>()
    for (line in input) {
        val p = line.split(",")
        notes.add(when (p[0]) {
            "warn" -> Warning(p[1])
            "remind" -> Reminder(p[1], p[2].toInt())
            else -> Notification(p[1])
        })
    }
    for (n in notes) println(n.render())
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: Kotlin 在线编辑器