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挑战
简单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())
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Kotlin 在线编辑器