Menu
CoddyTech

声明接口

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

接口会列出一种类型可以做什么,但不会说明具体如何实现。它声明了每个实现类都必须提供的方法和属性。类使用冒号来实现接口,和继承超类时一样,但不使用括号,因为接口没有构造函数:

interface Drawable {
    fun draw(): String
}
class Circle(val radius: Int) : Drawable {
    override fun draw() = "circle with radius $radius"
}
class Line(val length: Int) : Drawable {
    override fun draw() = "-".repeat(length)
}

在 main 中:

println(Circle(3).draw())
println(Line(5).draw())

输出:

circle with radius 3
-----

接口也可以声明属性。类会通过构造函数属性、存储属性或 getter 提供这些属性;接口本身不存储任何内容:

interface Vehicle {
    val wheels: Int
    val label: String
}
class Car(override val label: String) : Vehicle {
    override val wheels = 4
}
class Bike : Vehicle {
    override val wheels = 2
    override val label: String
        get() = "bike on $wheels wheels"
}

在 main 中:

println("${Car("taxi").label}: ${Car("taxi").wheels}")
println(Bike().label)

输出:

taxi: 4
bike on 2 wheels

接口声明的每个成员都必须实现,并且每个成员都要使用 override,否则类无法编译。接口不能被实例化:

interface Speaker {
    fun speak(): String
    val volume: Int
}
// class Mute : Speaker { override fun speak() = "" }   // 错误:未实现 volume
// class Loud : Speaker() { ... }                      // 错误:接口没有构造函数
// val s = Speaker()                                   // 错误:不能创建接口的实例

接口和抽象类都可以声明没有函数体的成员。接口没有构造函数,也不保存状态;类可以实现多个接口,但只能继承一个类。对于不相关的类共有的能力,例如 Drawable 或 Comparable,使用接口;对于带有状态的公共基类,使用抽象类。

interface Drawable { fun draw(): String }                   // 一种能力
abstract class Shape(val name: String) { abstract fun area(): Double }   // 带有状态的基类
class Square(val s: Double) : Shape("square"), Drawable {  // 一个类,多个接口
    override fun area() = s * s
    override fun draw() = "[]"
}
challenge icon

挑战

简单

声明接口 Shape 的成员:只读属性 name,以及返回 Double 的方法 area() 和 perimeter()。让 Rectangle(width, height)(名称为 rectangle)和 Circle(radius)(名称为 circle,使用 Math.PI)实现这些成员。然后完成 describe(shape),它会返回保留两位小数的 rectangle: area 12.00, perimeter 14.00,且只能使用 Shape 的成员。

提供的代码会读取 r,3,4 或 c,2 这样的行,创建对应的形状,并打印 describe(shape)。

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

亲手试试

fun main() {
    // 提供的输入输出代码:保持原样
    val input = generateSequence(::readLine).toList()
    for (line in input) {
        val p = line.split(",").map { it.trim() }
        val shape: Shape = if (p[0] == "r") Rectangle(p[1].toDouble(), p[2].toDouble()) else Circle(p[1].toDouble())
        println(describe(shape))
    }
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: Kotlin 在线编辑器