Menu
CoddyTech

开放类与子类

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

继承允许一个类基于另一个类构建。子类会获得超类的所有属性和方法,还可以添加自己的属性和方法。Kotlin 中的类默认是封闭的,因此必须先将类标记为 open,其他类才能继承它:

open class Animal(val name: String) {
    fun describe() = "$name is an animal"
}

class Dog(name: String) : Animal(name) {
    fun fetch() = "$name fetches the ball"
}

在 main 中:

val rex = Dog("Rex")
println(rex.describe())
println(rex.fetch())

输出:

Rex is an animal
Rex fetches the ball

class Dog(name: String) : Animal(name) 表示 Dog 扩展了 Animal,并将 name 传递给超类构造函数。参数没有 val,因为 Animal 中已经存在该属性。不能扩展非 open 类:

class Plant(val name: String)
// class Tree(name: String) : Plant(name)   // 错误:此类型是 final,不能被继承

open class Vehicle(val wheels: Int)
class Bike : Vehicle(2)                     // 传入一个固定值
class Truck(val load: Int) : Vehicle(6)     // 添加自己的属性

Dog 是一种 Animal,因此在需要超类类型的任何地方,都可以使用子类实例。一个 List<Animal> 可以存放狗、猫和普通动物,并且每个元素都有 Animal 的成员:

open class Animal(val name: String) {
    fun describe() = "$name is an animal"
}
class Dog(name: String) : Animal(name)
class Cat(name: String, val indoor: Boolean) : Animal(name)

在 main 中:

val pets: List<Animal> = listOf(Dog("Rex"), Cat("Tom", true), Animal("Generic"))
for (p in pets) println(p.describe())

输出:

Rex is an animal
Tom is an animal
Generic is an animal

继承表示“是一个”的关系:狗是一种动物,储蓄账户是一种账户。当一个类只是使用另一个类时(汽车有一个发动机),应改为给它添加一个该类型的属性。Kotlin 中的类默认是封闭的,因此,只有明确要允许扩展的类才会用 open 标记,其他类都能避免子类改变其行为。

open class Account(val owner: String)
class SavingsAccount(owner: String) : Account(owner)   // is-a:继承关系

class Engine(val horsepower: Int)
class Car(val engine: Engine)                          // has-a:包含一个属性
challenge icon

挑战

简单

Manager 重复了 Employee 已有的内容。将 Employee 设为开放类,并将 Manager 变成它的子类:Manager(name: String, salary: Int) 将两个值传给 Employee,并且只保留新增的内容,即一个私有列表,用于存储汇报对象的姓名,并提供 addReport(name) 和 teamSize()。在 Employee 中,raise(percent) 按指定百分比提高薪水,结果向下取整;describe() 返回 Ada earns 5500。

提供的代码会根据第一行(name,salary)创建一个经理,将后续每个姓名添加为汇报对象,涨薪 10%,并输出 Ada earns 5500 and leads 2,然后检查经理是否是 Employee。

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

亲手试试

fun main() {
    // 已提供的输入输出代码:保持原样
    val input = generateSequence(::readLine).toList()
    val (name, salary) = input[0].split(",")
    val boss = Manager(name, salary.toInt())
    for (report in input.drop(1)) boss.addReport(report)
    boss.raise(10)
    println("${boss.describe()} and leads ${boss.teamSize()}")
    println("a manager is an employee: ${(boss as Any) is Employee}")
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: Kotlin 在线编辑器