Kotlin 接口的默认实现详解
Kotlin 接口的默认实现是 Kotlin 与 Java 8+ 都支持的特性,但 Kotlin 的实现更加灵活和强大。下面是详细解析:
1. 基本默认实现
kotlin
interface Printer {
// 抽象方法(必须实现)
fun print(document: String)
// 默认实现方法(可选重写)
fun preview(document: String) {
println("预览文档: $document")
}
// 带返回值的默认实现
fun getDefaultPageSize(): Int {
return 210 to 297 // Pair 类型
}
}
class LaserPrinter : Printer {
// 只必须实现抽象方法
override fun print(document: String) {
println("激光打印: $document")
}
// 可以选择重写默认方法
override fun preview(document: String) {
println("激光打印机预览: $document")
}
}
2. 默认实现的不同形式
表达式体默认实现
kotlin
interface Calculator {
// 使用表达式体的默认实现
fun add(a: Int, b: Int): Int = a + b
fun subtract(a: Int, b: Int): Int = a - b
// 复杂默认实现
fun calculate(expression: String): Int {
return when {
expression.contains("+") -> {
val nums = expression.split("+")
nums[0].trim().toInt() + nums[1].trim().toInt()
}
expression.contains("-") -> {
val nums = expression.split("-")
nums[0].trim().toInt() - nums[1].trim().toInt()
}
else -> 0
}
}
}
使用其他接口方法
kotlin
interface Shape {
fun area(): Double
fun perimeter(): Double
// 默认实现可以调用抽象方法
fun description(): String {
return "面积: ${area()}, 周长: ${perimeter()}"
}
}
class Circle(val radius: Double) : Shape {
override fun area(): Double = Math.PI * radius * radius
override fun perimeter(): Double = 2 * Math.PI * radius
// 使用默认的 description() 实现
}
3. 属性默认实现
kotlin
interface User {
// 抽象属性(必须实现)
val username: String
// 带 getter 的默认实现属性
val displayName: String
get() = "User: $username"
// 带 setter 的默认实现(Kotlin 1.6.20+)
var email: String
get() = "$username@example.com"
set(value) {
// 可以在这里添加验证逻辑
require(value.contains("@")) { "Invalid email" }
// 但注意:接口属性没有 backing field,不能直接存储值
}
}
class Member(override val username: String) : User {
// 提供存储空间
private var _email: String = "$username@default.com"
override var email: String
get() = _email
set(value) {
require(value.contains("@")) { "Invalid email" }
_email = value
}
}
4. 默认实现中的多继承冲突解决
kotlin
interface A {
fun foo() {
println("A.foo")
}
fun bar()
}
interface B {
fun foo() {
println("B.foo")
}
fun bar() {
println("B.bar")
}
}
// 实现类必须解决冲突
class C : A, B {
// foo() 在两个接口都有默认实现,必须重写
override fun foo() {
// 选择调用特定接口的实现
super<A>.foo()
super<B>.foo()
println("C.foo")
}
// bar() 只在 B 中有默认实现,可以这样处理:
override fun bar() {
super<B>.bar() // 调用 B 的实现
// 或者提供完全不同的实现
}
}
更复杂的冲突解决
kotlin
interface Clickable {
fun click() = println("Clickable clicked")
fun showOff() = println("我是可点击的!")
}
interface Focusable {
fun focus() = println("获得焦点")
fun showOff() = println("我是可聚焦的!")
}
class Button : Clickable, Focusable {
override fun click() {
super.click()
println("按钮被点击")
}
// 必须重写 showOff() 解决冲突
override fun showOff() {
// 明确指定调用哪个父接口的实现
super<Clickable>.showOff()
super<Focusable>.showOff()
}
}
5. 默认实现中的私有方法和属性
kotlin
interface Logger {
fun log(message: String)
// 公共默认方法
fun logInfo(message: String) {
logWithTimestamp("[INFO] $message")
}
fun logError(message: String) {
logWithTimestamp("[ERROR] $message")
}
// 私有辅助方法(Kotlin 1.7+)
private fun logWithTimestamp(message: String) {
val timestamp = java.time.LocalDateTime.now()
log("[$timestamp] $message")
}
}
class ConsoleLogger : Logger {
override fun log(message: String) {
println(message)
}
}
// 使用
val logger = ConsoleLogger()
logger.logInfo("系统启动") // 自动加上时间戳
6. 接口默认实现与抽象类的区别
kotlin
// 接口:不能存储状态,但可以有默认实现
interface Repository {
fun save(data: String)
fun delete(id: String)
// 接口可以有默认实现
fun exists(id: String): Boolean {
return load(id) != null
}
fun load(id: String): String? // 抽象方法
}
// 抽象类:可以有状态和构造函数
abstract class AbstractRepository {
// 可以有状态(存储字段)
protected val cache = mutableMapOf<String, String>()
// 可以有构造函数
constructor(name: String) {
println("初始化仓库: $name")
}
// 抽象方法
abstract fun save(data: String)
// 具体方法(需要 open 才能被重写)
open fun delete(id: String) {
cache.remove(id)
}
// 可以有 final 方法(不能被重写)
fun clearCache() {
cache.clear()
}
}
7. 默认实现的进阶用法
为现有接口添加扩展
kotlin
interface Listener {
fun onEvent(event: String)
}
// 为接口添加默认实现(实际上是为实现类添加扩展)
fun Listener.onEventWithDefault() {
onEvent("default event")
}
class MyListener : Listener {
override fun onEvent(event: String) {
println("收到事件: $event")
}
}
// 使用
val listener = MyListener()
listener.onEventWithDefault() // 调用扩展函数
模板方法模式
kotlin
interface DataProcessor {
// 模板方法:定义算法骨架
fun process(data: String): String {
val validated = validate(data)
val transformed = transform(validated)
return finalize(transformed)
}
// 可重写的步骤
open fun validate(data: String): String {
require(data.isNotBlank()) { "数据不能为空" }
return data.trim()
}
abstract fun transform(data: String): String
open fun finalize(data: String): String {
return "$data [已处理]"
}
}
class UppercaseProcessor : DataProcessor {
override fun transform(data: String): String {
return data.uppercase()
}
// 可以选择重写其他步骤
override fun validate(data: String): String {
return super.validate(data).take(100) // 限制长度
}
}
8. Java 互操作性
Kotlin 接口的默认实现在 Java 中的表现
kotlin
// Kotlin 接口
interface KInterface {
fun required()
fun optional() {
println("默认实现")
}
}
// Java 中使用
public class JavaClass implements KInterface {
@Override
public void required() {
System.out.println("必须实现");
}
// 可选:重写 optional() 或不重写
@Override
public void optional() {
// 调用默认实现
KInterface.DefaultImpls.optional(this);
// 或者提供自己的实现
}
}
使用 @JvmDefault 注解(Kotlin 1.2-1.3)
kotlin
// 旧版本兼容性
interface OldInterface {
@JvmDefault
fun defaultMethod() {
println("兼容 Java 8 之前的默认方法")
}
}
9. 默认实现的限制和注意事项
kotlin
interface LimitedInterface {
// 注意:接口不能有构造函数
// constructor() {} // 错误!
// 不能有初始化块
// init { println("初始化") } // 错误!
// 不能有幕后字段(field)
var value: String
get() = "default"
set(value) {
// field = value // 错误!接口不能有 field
}
// 解决方法:使用抽象属性 + 默认 getter/setter
abstract var realValue: String
var delegatedValue: String
get() = realValue
set(value) { realValue = value }
}
10. 实用设计模式
组合代替继承
kotlin
interface Behavior {
fun act()
}
class Walking : Behavior {
override fun act() = println("走路")
}
class Flying : Behavior {
override fun act() = println("飞行")
}
class Swimming : Behavior {
override fun act() = println("游泳")
}
// 使用接口组合
class Duck {
private val behaviors = mutableListOf<Behavior>()
fun addBehavior(behavior: Behavior) {
behaviors.add(behavior)
}
fun perform() {
behaviors.forEach { it.act() }
}
}
// 配置不同的行为组合
val duck = Duck()
duck.addBehavior(Walking())
duck.addBehavior(Swimming())
duck.perform()
策略模式
kotlin
interface DiscountStrategy {
fun calculate(price: Double): Double
}
class NoDiscount : DiscountStrategy {
override fun calculate(price: Double): Double = price
}
class PercentageDiscount(val percentage: Double) : DiscountStrategy {
override fun calculate(price: Double): Double = price * (1 - percentage / 100)
}
class FixedDiscount(val amount: Double) : DiscountStrategy {
override fun calculate(price: Double): Double = maxOf(0.0, price - amount)
}
class ShoppingCart(private var strategy: DiscountStrategy = NoDiscount()) {
var total: Double = 0.0
fun addItem(price: Double) {
total += price
}
fun checkout(): Double {
return strategy.calculate(total)
}
fun setStrategy(newStrategy: DiscountStrategy) {
strategy = newStrategy
}
}
11. 测试接口的默认实现
kotlin
interface Repository {
fun save(item: String): Boolean
// 默认实现
fun saveAll(items: List<String>): List<Boolean> {
return items.map { save(it) }
}
}
// 测试默认实现
@Test
fun testDefaultImplementation() {
val mockRepository = object : Repository {
val savedItems = mutableListOf<String>()
override fun save(item: String): Boolean {
savedItems.add(item)
return true
}
}
val items = listOf("a", "b", "c")
val results = mockRepository.saveAll(items)
assertEquals(3, results.size)
assertEquals(listOf("a", "b", "c"), mockRepository.savedItems)
}
总结要点
-
默认实现是可选重写的:实现类可以选择使用默认实现或提供自己的实现
-
解决多继承冲突:当多个接口有相同签名的默认方法时,实现类必须重写并指定使用哪个
-
接口 vs 抽象类:
- 接口:不能存储状态,支持多继承,有默认实现
- 抽象类:可以存储状态,单继承,可以有具体方法和抽象方法
-
Java 互操作 :Kotlin 的默认方法在 Java 中可见为带有
DefaultImpls内部类 -
私有方法:Kotlin 1.7+ 支持接口中的私有方法,用于辅助默认实现
-
实用模式:默认实现使得接口可以用于模板方法、策略模式等设计模式
markdownKotlin 接口的默认实现提供了强大的灵活性,使得接口不仅可以定义契约,还可以提供通用行为,促进了代码重用和可扩展性。