覆盖成员
本课属于 Coddy Kotlin 学习旅程的“面向对象编程”单元。第 18 课,共 57 课。
子类可以用自己的版本替换继承的方法。超类将方法标记为 open,子类则使用 override 再次声明它:
open class Animal(val name: String) {
open fun sound() = "..."
}
class Dog(name: String) : Animal(name) {
override fun sound() = "Woof"
}
class Cat(name: String) : Animal(name) {
override fun sound() = "Meow"
}在 main 中:
println(Dog("Rex").sound())
println(Cat("Tom").sound())
println(Animal("Generic").sound())输出:
Woof
Meow
...实际运行的版本由对象的实际类决定,即使变量的类型是超类也一样。超类中的代码调用开放方法时,也会使用子类的版本:
open class Animal(val name: String) {
open fun sound() = "..."
fun speak() = "$name says ${sound()}"
}
class Dog(name: String) : Animal(name) {
override fun sound() = "Woof"
}在 main 中:
val pets: List<Animal> = listOf(Dog("Rex"), Animal("Generic"))
for (p in pets) println(p.speak())输出:
Rex says Woof
Generic says ...属性也可以用同样的方式重写:在超类中使用 open val,在子类中使用 override val,可以将其声明为普通属性、构造函数属性或计算属性 getter:
open class Shape {
open val name = "shape"
open val corners = 0
}
class Triangle : Shape() {
override val name = "triangle"
override val corners = 3
}
class Polygon(override val corners: Int) : Shape() {
override val name: String
get() = "$corners-gon"
}在 main 中:
for (s in listOf(Shape(), Triangle(), Polygon(6))) println("${s.name}: ${s.corners}")输出:
shape: 0
triangle: 3
6-gon: 6标记为 override 的成员会再次开放,因此子类的子类可以再次重写它;final override 会阻止这种情况。没有 open 的成员完全不能被重写,子类也不能声明具有相同签名的成员:
open class Animal {
open fun sound() = "..."
fun sleep() = "zzz"
}
open class Dog : Animal() {
final override fun sound() = "Woof"
}
class Puppy : Dog() {
// override fun sound() = "Yip" // 错误:'Dog' 中的 'sound' 是 final,不能重写
// fun sleep() = "nap" // 错误:'sleep' 隐藏了父类的一个成员
}挑战
简单Animal 有 legs()(4)、sound()(...)和 describe(),后者返回由 legs() 和 sound() 生成的 Rex has 4 legs and says Woof。让 legs() 和 sound() 可以被重写,并且只重写这两个方法来完成子类:Dog 发出 Woof 声,Bird 有 2 条腿并发出 Tweet 声,Snake 有 0 条腿并发出 Hiss 声。describe() 在 Animal 中保持原样。
提供的代码会读取 dog,Rex、bird,Pip、snake,Kaa 或其他任意类型的行(对应一个普通的 Animal),将这些动物存储在一个 List<Animal> 中,并为每个动物打印 describe() 的结果。
你的代码应写在 Animal.kt、Dog.kt、Bird.kt 和 Snake.kt 中。Main.kt 包含提供的输入/输出代码,不能编辑。
亲手试试
fun main() {
// 已提供的输入输出代码:保持原样
val input = generateSequence(::readLine).toList()
val animals = mutableListOf<Animal>()
for (line in input) {
val (kind, name) = line.split(",")
animals.add(when (kind) {
"dog" -> Dog(name)
"bird" -> Bird(name)
"snake" -> Snake(name)
else -> Animal(name)
})
}
for (a in animals) println(a.describe())
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Kotlin 在线编辑器