1. 概述
本文将介绍如何在 Kotlin 的接口中定义 Companion Object,并解释其对实现类的影响。同时,我们还会展示如何通过 Companion Object 实现接口。内容通俗易懂,适合有一定 Kotlin 基础的开发者阅读。
2. 在接口中使用 Companion Object
在 Kotlin 中,接口中定义 Companion Object 的方式与类中完全一致。我们来看一个 Vehicle
接口的例子:
interface Vehicle {
fun getNumberOfWheels(): Int
companion object {
const val DOUBLE_TRACK_AMOUNT_OF_WHEELS = 3
fun isDoubleTrack(vehicle: Vehicle) = vehicle.getNumberOfWheels() > DOUBLE_TRACK_AMOUNT_OF_WHEELS
}
}
这个 Companion Object 定义了一个常量 DOUBLE_TRACK_AMOUNT_OF_WHEELS
和一个工具方法 isDoubleTrack()
,用于判断车辆是否为双轨类型(即轮子数量是否大于 3)。
✅ 常见使用场景:接口中 Companion Object 通常用于存放常量或工具方法。
3. 实现包含 Companion Object 的接口
接口中的 Companion Object 不会影响接口的实现逻辑,也就是说它并不改变接口契约。它只是与接口绑定的一个“附属对象”,其本质是一个单例。
我们来看一个实现 Vehicle
接口的 Car
类:
class Car(val brand: String, val model: String, val age: Int) : Vehicle {
companion object {
const val ANTIQUE_CAR_MINIMAL_AGE = 30
}
override fun getNumberOfWheels() = 4
fun isAntique() = age >= ANTIQUE_CAR_MINIMAL_AGE
}
可以看到,Car
类实现了 Vehicle
接口,并拥有自己的 Companion Object。这与接口中的 Companion Object 没有任何关系,各自独立存在。
4. 在 Companion Object 中实现接口
Kotlin 允许我们在 Companion Object 中直接实现接口。我们使用命名 Companion Object 来实现 Vehicle
接口:
class VehicleImplementedInCompanionObject {
companion object Bicycle : Vehicle {
override fun getNumberOfWheels(): Int {
return 2
}
}
}
✅ 接口在类中实现 和 在 Companion Object 中实现,本质上没有区别。
为了验证这一点,我们分别测试 Car
和 Bicycle
实例的 getNumberOfWheels()
方法调用:
测试 Car 实例
@Test
fun `given type implementing Vehicle, when use should work`() {
val car = Car("Ford", "Mustang", 12)
assertThat(car.getNumberOfWheels()).isEqualTo(4)
assertThat(Vehicle.isDoubleTrack(car)).isTrue
}
测试 Bicycle 实例(Companion Object)
@Test
fun `given companion object implementing Vehicle, when use should work`() {
val bicycle = VehicleImplementedInCompanionObject.Bicycle
assertThat(bicycle.getNumberOfWheels()).isEqualTo(2)
assertThat(Vehicle.isDoubleTrack(bicycle)).isFalse
}
⚠️ 注意:Car
可以创建多个实例,而 Bicycle
是单例,始终指向同一个对象。
5. 总结
本文我们学习了:
- 如何在 Kotlin 接口中定义 Companion Object
- Companion Object 不影响接口实现逻辑
- 如何在 Companion Object 中实现接口
- Companion Object 实现接口与类实现接口本质上没有区别
最终结论是:接口中 Companion Object 的存在不会改变接口契约,它主要用于定义常量和工具方法。接口的实现可以在类中,也可以在 Companion Object 中完成,使用方式一致。
完整示例代码请查看 GitHub 仓库。