Kotlin 接口关键字
最后修改于 2025 年 4 月 19 日
Kotlin 接口定义了类可以实现的契约。它们可以包含抽象方法和属性,以及默认实现。接口支持 Kotlin 中的多态性和多重继承。本教程通过实际示例深入探讨了 interface
关键字。
基本定义
Kotlin 中的接口是类的蓝图。它包含抽象方法声明和方法实现。接口不能存储状态,但可以拥有属性。类使用 :
语法实现接口。一个类可以实现多个接口。
基本接口声明
最简单的接口包含抽象方法声明。实现接口的类必须为这些方法提供具体的实现。这强制执行了一个契约,实现类必须遵守该契约。
package com.zetcode interface Greeter { fun greet(): String } class Person : Greeter { override fun greet(): String { return "Hello!" } } fun main() { val person = Person() println(person.greet()) // Output: Hello! }
在这里,我们定义了一个带有抽象方法的 Greeter
接口。Person
类实现了这个接口,并提供了方法体。实现接口方法时需要 override
关键字。
具有默认实现的接口
Kotlin 接口可以为方法提供默认实现。实现接口的类可以使用这些默认值或覆盖它们。在某些情况下,此功能使接口比抽象类更灵活。
package com.zetcode interface Vehicle { fun start() { println("Vehicle started") } fun stop() } class Car : Vehicle { override fun stop() { println("Car stopped") } } fun main() { val car = Car() car.start() // Output: Vehicle started car.stop() // Output: Car stopped }
Vehicle
接口为 start
提供了默认实现,但将 stop
保持为抽象。Car
类只需要实现 stop
并继承默认的 start
行为。
接口属性
接口可以声明实现类必须提供的抽象属性。这些属性可以实现为字段或通过 getter。接口属性不能有后备字段,但可以有自定义访问器。
package com.zetcode interface User { val name: String val age: Int get() = 0 // Default implementation } class RegisteredUser(override val name: String) : User { // age uses default implementation } fun main() { val user = RegisteredUser("John Doe") println("${user.name}, ${user.age}") // Output: John Doe, 0 }
User
接口声明了两个属性。name
是抽象的,必须实现,而 age
具有默认值。RegisteredUser
类将 name
实现为属性并使用默认的 age
实现。
多接口实现
Kotlin 支持多接口继承。一个类可以实现多个接口,继承它们的所有成员。如果存在方法冲突,实现类必须显式解决它们。
package com.zetcode interface Flyable { fun fly() { println("Flying high") } } interface Swimmable { fun swim() { println("Swimming deep") } } class Duck : Flyable, Swimmable { fun describe() { fly() swim() } } fun main() { val duck = Duck() duck.describe() // Output: // Flying high // Swimming deep }
Duck
类同时实现了 Flyable
和 Swimmable
接口。它可以调用这两个接口的方法。这演示了 Kotlin 通过接口对行为的多重继承的支持。
解决方法冲突
当多个接口声明了具有相同签名的方法时,实现类必须解决冲突。这是通过覆盖该方法并指定要使用哪个接口的实现来完成的。
package com.zetcode interface A { fun foo() { println("A's foo") } } interface B { fun foo() { println("B's foo") } } class C : A, B { override fun foo() { super<A>.foo() super<B>.foo() println("C's foo") } } fun main() { val c = C() c.foo() // Output: // A's foo // B's foo // C's foo }
C
类实现了同时具有冲突 foo
方法的 A
和 B
。该类通过使用 super<Interface>
语法调用两个实现并添加其自身行为来解决此问题。
函数式接口 (SAM 接口)
单抽象方法 (SAM) 接口可以使用 lambda 实现。这些在 Kotlin 中被称为函数式接口。fun
修饰符将接口标记为函数式接口。
package com.zetcode fun interface StringProcessor { fun process(input: String): String } fun main() { val upperCaseProcessor = StringProcessor { it.uppercase() } val lowerCaseProcessor = StringProcessor { it.lowercase() } println(upperCaseProcessor.process("Hello")) // Output: HELLO println(lowerCaseProcessor.process("World")) // Output: world }
StringProcessor
接口使用 fun
标记,使其成为函数式接口。我们使用 lambda 创建实例,而不是完整的类实现。这为简单的接口实现提供了简洁的语法。
接口继承
接口可以从其他接口继承,形成接口层次结构。子接口包括其父接口的所有成员。实现类必须满足整个层次结构的所有要求。
package com.zetcode interface Animal { fun eat() } interface Mammal : Animal { fun nurse() } class Human : Mammal { override fun eat() { println("Eating food") } override fun nurse() { println("Nursing young") } } fun main() { val human = Human() human.eat() // Output: Eating food human.nurse() // Output: Nursing young }
Mammal
接口扩展了 Animal
,继承了它的 eat
方法。Human
类实现了 Mammal
,并且必须为 eat
和 nurse
提供实现。这展示了接口层次结构在 Kotlin 中的工作方式。
接口的最佳实践
- 优先使用接口而不是抽象类: 尽可能使用接口来定义契约,因为它们支持多重继承。
- 明智地使用默认实现: 为在不同实现之间具有通用行为的方法提供默认实现。
- 保持接口专注: 遵循接口隔离原则 - 接口应该小而专注。
- 文档接口契约: 清楚地记录实现者必须提供的内容以及调用者可以期望的内容。
- 考虑函数式接口: 当单个抽象方法足以满足契约时,使用 SAM 接口。
来源
本教程深入探讨了 Kotlin 的 interface
关键字,展示了基本声明、默认方法、属性和多重继承。我们探讨了各种场景,包括方法冲突和函数式接口。正确使用接口可以使您的代码更灵活、更易于维护。
作者
列出 所有 Kotlin 教程。