1. Kotlin接口基础概念解析
Kotlin接口是一种定义行为契约的强大工具,它允许我们声明一组抽象方法和属性,而无需关心具体实现。与Java接口相比,Kotlin接口具有更丰富的特性,这也是为什么它成为现代Kotlin开发中不可或缺的部分。
1.1 接口的本质与作用
接口在Kotlin中通过interface关键字定义,它本质上是一组抽象成员的集合。与抽象类不同,接口不能保存状态(尽管可以通过属性访问器实现类似功能),这使得它成为定义纯行为的理想选择。
接口的核心价值体现在三个方面:
- 多继承支持:Kotlin类可以实现多个接口,解决了单继承语言的局限性
- 契约式编程:明确规定了实现类必须提供哪些功能
- 解耦:将定义与实现分离,提高代码的灵活性和可维护性
interface Clickable { fun click() fun showOff() = println("I'm clickable!") // 带默认实现的方法 }1.2 接口与抽象类的区别
虽然接口和抽象类都包含抽象成员,但它们有本质区别:
| 特性 | 接口 | 抽象类 |
|---|---|---|
| 继承机制 | 可实现多个 | 只能继承一个 |
| 状态保存 | 不能保存状态 | 可以保存状态 |
| 构造函数 | 不能有主/次构造函数 | 可以有构造函数 |
| 成员初始化 | 属性不能初始化 | 属性可以初始化 |
| 使用场景 | 定义行为契约 | 提供部分实现 |
实际开发中的经验法则:当你主要需要定义一组相关操作时使用接口,当需要共享代码或维护状态时考虑抽象类。
2. Kotlin接口的高级特性
2.1 默认方法实现
Kotlin接口允许为方法提供默认实现,这是与Java 8之前接口的重大区别。这个特性使得接口演化变得更加容易——你可以向接口添加新方法并提供默认实现,而不必强制所有实现类都立即实现新方法。
interface UserRepository { fun add(user: User) fun get(id: Int): User? // 默认实现 fun contains(id: Int): Boolean { return get(id) != null } }注意事项:
- 默认方法会带来"菱形继承"问题,当多个接口有相同方法签名时,实现类必须明确指定使用哪个默认实现
- 默认方法不应包含复杂逻辑,保持简单职责
- 避免在默认方法中访问状态,这可能导致意外行为
2.2 属性声明
Kotlin接口可以声明属性,但这些属性要么是抽象的,要么必须提供访问器实现。接口中的属性不能有幕后字段(field),因此不能直接初始化。
interface Person { val name: String // 抽象属性 val age: Int // 提供getter实现 get() = 0 }实现类可以通过多种方式满足接口属性要求:
class Employee(override val name: String) : Person { // age使用接口默认实现 } class Student : Person { override val name: String get() = "Student" override val age: Int = 20 // 也可以覆盖 }2.3 函数式接口(SAM接口)
对于只有一个抽象方法的接口(Single Abstract Method,简称SAM),Kotlin提供了特殊的语法糖,允许使用lambda表达式实现:
fun interface Transformer { fun transform(input: String): String } val upperCaseTransformer = Transformer { it.uppercase() }使用场景:
- 事件监听器
- 回调函数
- 策略模式实现
从Kotlin 1.4开始,必须显式使用
fun interface声明才能启用SAM转换功能。
3. 接口的继承与组合
3.1 接口继承
Kotlin接口可以继承其他接口,形成接口层次结构。这允许我们构建更精细的契约:
interface Clickable { fun click() } interface Scrollable : Clickable { fun scroll() fun showOff() = println("I'm scrollable!") } class Page : Scrollable { override fun click() = println("Page clicked") override fun scroll() = println("Page scrolled") // 可以选择是否覆盖showOff }3.2 多接口继承冲突解决
当实现多个接口且这些接口有相同方法签名时,必须明确指定使用哪个实现:
interface A { fun foo() { println("A") } } interface B { fun foo() { println("B") } } class C : A, B { override fun foo() { super<A>.foo() // 明确调用A的实现 super<B>.foo() // 明确调用B的实现 } }最佳实践:
- 避免设计有方法签名冲突的接口
- 如果冲突不可避免,在实现类中提供明确解决方案
- 考虑使用组合代替多重继承
3.3 接口委托
Kotlin通过by关键字支持委托模式,这是处理接口实现的强大工具:
interface DataStorage { fun save(data: String) fun load(): String } class FileStorage : DataStorage { override fun save(data: String) { /* 实现 */ } override fun load(): String { /* 实现 */ } } class SecureStorage(private val storage: DataStorage) : DataStorage by storage { // 可以只覆盖部分方法 override fun save(data: String) { storage.save(encrypt(data)) } private fun encrypt(data: String): String { /* 加密逻辑 */ } }委托模式的优势:
- 实现真正的零样板代码委托
- 轻松实现装饰器模式
- 方便进行功能扩展和修改
4. Kotlin接口在实际项目中的应用
4.1 策略模式实现
接口是策略模式的天然实现方式:
interface DiscountStrategy { fun applyDiscount(amount: Double): Double } class NoDiscount : DiscountStrategy { override fun applyDiscount(amount: Double) = amount } class PercentageDiscount(private val percentage: Double) : DiscountStrategy { override fun applyDiscount(amount: Double) = amount * (1 - percentage/100) } class Order(private val discountStrategy: DiscountStrategy) { fun checkout(amount: Double): Double { return discountStrategy.applyDiscount(amount) } }4.2 回调机制
接口常用于实现回调机制:
interface DownloadCallback { fun onStart() fun onProgress(percent: Int) fun onComplete(data: ByteArray) fun onError(exception: Exception) } class FileDownloader(private val callback: DownloadCallback) { fun download(url: String) { callback.onStart() try { // 模拟下载 for (i in 1..100) { Thread.sleep(50) callback.onProgress(i) } callback.onComplete(ByteArray(0)) } catch (e: Exception) { callback.onError(e) } } }4.3 模块间通信
接口是模块间解耦的理想选择:
// 在core模块定义接口 interface AuthService { fun login(username: String, password: String): Boolean fun logout() } // 在app模块实现 class FirebaseAuthService : AuthService { override fun login(username: String, password: String): Boolean { // Firebase实现 } override fun logout() { // Firebase实现 } } // 在其他模块通过接口使用 class UserProfile(val authService: AuthService) { fun showProfile() { if (!authService.login("user", "pass")) { println("Login failed") } } }5. 接口设计的最佳实践与陷阱
5.1 接口设计原则
- 单一职责原则:每个接口应该只关注一个特定功能领域
- 小而美:保持接口精简,避免"胖接口"
- 命名清晰:使用
-able后缀命名行为接口(如Runnable、Comparable) - 文档完整:为所有公共接口成员提供KDoc文档
- 稳定性:一旦发布,尽量避免修改接口
5.2 常见陷阱与解决方案
陷阱1:过度使用默认方法
- 问题:默认方法过多会导致接口变得臃肿
- 解决方案:将相关默认方法提取到单独的接口或扩展函数中
陷阱2:接口泄漏
- 问题:内部实现细节通过接口暴露
- 解决方案:为不同客户端提供不同的接口视图
陷阱3:状态管理
- 问题:试图通过接口属性维护状态
- 解决方案:使用抽象类或组合模式来管理状态
5.3 接口与扩展函数的结合
Kotlin扩展函数可以与接口协同工作,提供更灵活的设计:
interface JsonSerializable { fun toJson(): String } // 为所有JsonSerializable提供扩展函数 fun JsonSerializable.prettyPrint(): String { return JsonParser.parseString(toJson()).toString() } class User : JsonSerializable { override fun toJson() = """{"name":"John"}""" } // 使用 val user = User() println(user.prettyPrint())这种组合方式允许我们:
- 保持接口精简
- 通过扩展添加辅助功能
- 实现功能的按需导入
6. Kotlin接口在Android开发中的实际案例
6.1 RecyclerView适配器中的接口
interface OnItemClickListener<T> { fun onItemClick(item: T, position: Int) } class MyAdapter<T>( private val items: List<T>, private val listener: OnItemClickListener<T> ) : RecyclerView.Adapter<MyViewHolder<T>>() { override fun onBindViewHolder(holder: MyViewHolder<T>, position: Int) { holder.bind(items[position]) holder.itemView.setOnClickListener { listener.onItemClick(items[position], position) } } } // 使用 adapter = MyAdapter(dataList, object : OnItemClickListener<Data> { override fun onItemClick(item: Data, position: Int) { // 处理点击 } })6.2 ViewModel与UI通信
interface LoginViewModel { val state: LiveData<LoginState> fun login(username: String, password: String) } class LoginActivity : AppCompatActivity() { private val viewModel: LoginViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) viewModel.state.observe(this) { state -> when (state) { is Loading -> showProgress() is Success -> navigateToHome() is Error -> showError(state.message) } } loginButton.setOnClickListener { viewModel.login( usernameEditText.text.toString(), passwordEditText.text.toString() ) } } }6.3 跨模块依赖解耦
在大型Android项目中,接口是解耦模块依赖的关键:
// 在:features:profile模块定义 interface UserProfileDependencies { fun userRepository(): UserRepository fun imageLoader(): ImageLoader } // 在:app模块实现 class AppDependencies : UserProfileDependencies { override fun userRepository() = UserRepositoryImpl() override fun imageLoader() = GlideImageLoader() } // 在:features:profile模块使用 class ProfileViewModel(dependencies: UserProfileDependencies) { private val userRepo = dependencies.userRepository() private val imageLoader = dependencies.imageLoader() // ... }这种模式通过接口完全解耦了功能模块与应用基础设施的依赖关系。
7. Kotlin接口与协程的结合
7.1 异步操作接口
interface NewsRepository { suspend fun fetchLatestNews(): List<News> suspend fun fetchNewsDetail(id: String): NewsDetail } class NewsRepositoryImpl( private val api: NewsApi, private val db: NewsDatabase ) : NewsRepository { override suspend fun fetchLatestNews(): List<News> { return try { val news = api.getLatestNews() db.saveNews(news) news } catch (e: Exception) { db.getCachedNews() } } // ...其他实现 }7.2 Flow在接口中的应用
interface StockPriceMonitor { fun monitorStock(symbol: String): Flow<PriceUpdate> suspend fun getCurrentPrice(symbol: String): PriceUpdate } class RealStockPriceMonitor( private val stockService: StockService ) : StockPriceMonitor { override fun monitorStock(symbol: String): Flow<PriceUpdate> { return stockService.getPriceUpdates(symbol) .catch { e -> emit(PriceUpdate.Error(e)) } } override suspend fun getCurrentPrice(symbol: String): PriceUpdate { return try { stockService.getCurrentPrice(symbol) } catch (e: Exception) { PriceUpdate.Error(e) } } }7.3 协程作用域管理
interface CoroutineScopeOwner { val coroutineScope: CoroutineScope } class ActivityScopeOwner(activity: ComponentActivity) : CoroutineScopeOwner { override val coroutineScope: CoroutineScope = activity.lifecycleScope } class Presenter( scopeOwner: CoroutineScopeOwner, private val repository: NewsRepository ) { private val scope = scopeOwner.coroutineScope fun loadNews() { scope.launch { val news = repository.fetchLatestNews() // 更新UI } } }8. Kotlin接口的高级技巧与性能考量
8.1 内联类实现接口
Kotlin内联类可以实现接口,这在需要类型安全又不想引入运行时开销时非常有用:
interface Id { val value: String } @JvmInline value class UserId(override val value: String) : Id @JvmInline value class ProductId(override val value: String) : Id fun processUserId(id: UserId) { println("Processing user ${id.value}") } // 使用 val userId = UserId("123") val productId = ProductId("456") processUserId(userId) // 正确 // processUserId(productId) // 编译错误,类型不匹配8.2 接口与类型别名结合
类型别名可以简化复杂接口类型的声明:
typealias ItemClickListener<T> = (T, Int) -> Unit interface Adapter<T> { var itemClick: ItemClickListener<T> } class MyAdapter<T> : Adapter<T> { override var itemClick: ItemClickListener<T> = { _, _ -> } }8.3 接口性能考量
- 方法调用开销:接口方法调用比类方法调用稍慢(约10%),但在大多数情况下可以忽略
- 内存占用:每个接口实例会带来少量内存开销
- Proguard优化:合理配置Proguard可以减少接口带来的运行时开销
性能优化建议:
- 在性能关键路径避免深度接口继承
- 考虑使用final类实现高频调用的接口
- 对于简单接口,可以使用函数类型替代
8.4 接口与Kotlin/JS和Kotlin/Native
在多平台项目中,接口的行为可能有所不同:
Kotlin/JS:
- 接口编译为JavaScript的抽象方法
- 默认方法会被复制到实现类中
- 接口性能与ES6类相当
Kotlin/Native:
- 接口调用有与JVM类似的轻微开销
- 在iOS交互中,接口是定义Kotlin与Swift/Obj-C协议的最佳方式
// 多平台接口定义 expect interface PlatformFileSystem { fun readFile(path: String): String fun writeFile(path: String, content: String) } // JVM实现 actual class JvmFileSystem : PlatformFileSystem { actual override fun readFile(path: String): String { return File(path).readText() } actual override fun writeFile(path: String, content: String) { File(path).writeText(content) } }9. Kotlin接口的未来发展趋势
随着Kotlin语言的演进,接口功能仍在不断增强:
- 上下文接收器(Context Receivers): 未来版本可能会引入更优雅的接口组合方式
// 实验性功能 interface LoggingContext { val logger: Logger } context(LoggingContext) interface Service { fun execute() { logger.info("Executing...") } }多平台接口改进:
- 更好的平台特定接口实现检测
- 更高效的多平台接口代码生成
接口与元编程: 结合Kotlin的元编程能力,接口可能会支持更强大的运行时行为修改
10. 从Java接口到Kotlin接口的迁移策略
对于Java开发者转向Kotlin,接口使用有一些需要注意的差异点:
默认方法处理:
- Kotlin中所有非抽象接口方法都是默认方法
- 与Java 8+的默认方法二进制兼容
静态方法: Kotlin接口不能包含静态方法,应使用伴生对象或顶层函数替代
函数式接口: Kotlin中需要显式声明
fun interface才能获得SAM转换支持
迁移步骤建议:
- 将Java接口转换为Kotlin接口
- 检查所有默认方法实现
- 将静态方法转换为伴生对象成员
- 考虑将适合的接口标记为
fun interface - 利用Kotlin的属性语法简化getter/setter
示例迁移:
// Java接口 public interface DataProcessor { void process(Data data); default void validate(Data data) { // 验证逻辑 } static DataProcessor create() { return new DefaultDataProcessor(); } }// 迁移后的Kotlin接口 interface DataProcessor { fun process(data: Data) fun validate(data: Data) { // 验证逻辑 } companion object { fun create(): DataProcessor = DefaultDataProcessor() } }11. Kotlin接口在函数式编程中的应用
Kotlin支持函数式编程风格,接口在其中扮演重要角色:
11.1 代数数据类型(ADT)
sealed interface Result<out T> { data class Success<out T>(val value: T) : Result<T> data class Error(val exception: Throwable) : Result<Nothing> } fun handleResult(result: Result<String>) { when(result) { is Result.Success -> println(result.value) is Result.Error -> println("Error: ${result.exception}") } }11.2 高阶函数与接口
interface Transformer<T, R> { fun transform(input: T): R } fun <T, R> List<T>.map(transformer: Transformer<T, R>): List<R> { return this.map { transformer.transform(it) } } // 使用 val stringToLength = object : Transformer<String, Int> { override fun transform(input: String) = input.length } val lengths = listOf("a", "ab", "abc").map(stringToLength)11.3 函数式模式实现
Monad模式示例:
interface Monad<out T> { fun <R> flatMap(f: (T) -> Monad<R>): Monad<R> } class Maybe<out T>(val value: T?) : Monad<T> { override fun <R> flatMap(f: (T) -> Monad<R>): Monad<R> { return value?.let { f(it) } ?: Maybe(null) } }12. 接口与Kotlin DSL设计
接口是构建类型安全DSL的重要工具:
interface SqlQueryBuilder { fun select(vararg columns: String): SqlQueryBuilder fun from(table: String): SqlQueryBuilder fun where(condition: String): SqlQueryBuilder fun build(): String } class SimpleSqlQueryBuilder : SqlQueryBuilder { private val parts = mutableListOf<String>() override fun select(vararg columns: String): SqlQueryBuilder { parts.add("SELECT ${columns.joinToString(", ")}") return this } override fun from(table: String): SqlQueryBuilder { parts.add("FROM $table") return this } override fun where(condition: String): SqlQueryBuilder { parts.add("WHERE $condition") return this } override fun build(): String { return parts.joinToString(" ") } } // 使用 val query = SimpleSqlQueryBuilder() .select("id", "name", "email") .from("users") .where("age > 21") .build()DSL设计技巧:
- 使用接口定义DSL语法
- 通过返回
this实现流畅接口 - 为常用操作提供扩展函数
- 使用带接收者的lambda进一步简化语法
13. 接口与依赖注入框架
现代依赖注入框架如Koin、Dagger等都重度依赖接口:
13.1 Koin示例
interface DatabaseService { fun executeQuery(sql: String): ResultSet } class ProductionDatabaseService : DatabaseService { override fun executeQuery(sql: String): ResultSet { // 实际数据库操作 } } // 模块定义 val appModule = module { single<DatabaseService> { ProductionDatabaseService() } } // 使用 class UserRepository(private val db: DatabaseService) { fun getUsers(): List<User> { val result = db.executeQuery("SELECT * FROM users") // 处理结果 } }13.2 接口与测试替身
接口使得创建测试替身(Test Double)变得简单:
class TestDatabaseService : DatabaseService { private val data = mutableMapOf<String, List<Map<String, Any>>>() fun addTestData(table: String, rows: List<Map<String, Any>>) { data[table] = rows } override fun executeQuery(sql: String): ResultSet { // 解析SQL并返回测试数据 return MockResultSet(data) } } class UserRepositoryTest { @Test fun testGetUsers() { val testDb = TestDatabaseService().apply { addTestData("users", listOf( mapOf("id" to 1, "name" to "Alice"), mapOf("id" to 2, "name" to "Bob") )) } val repo = UserRepository(testDb) val users = repo.getUsers() assertEquals(2, users.size) } }14. Kotlin接口的调试与性能分析
14.1 调试接口调用
断点技巧:
- 在接口方法上设置断点会捕获所有实现类的调用
- 使用条件断点过滤特定实现类
调用栈分析:
- 注意接口方法调用的间接性
- 使用"Show Implementations"功能快速导航到具体实现
14.2 性能分析
CPU分析:
- 接口方法调用在调用图上显示为"invokeinterface"
- 对比直接方法调用("invokevirtual")的开销
内存分析:
- 接口引用比类引用多消耗约4字节内存
- 注意接口作为集合元素类型时的内存影响
优化建议:
- 对高频调用的热路径考虑使用final类
- 在性能关键代码中减少接口层次深度
- 必要时使用内联类包装接口实现
15. 接口与Kotlin元编程
Kotlin的反射API可以用于接口的运行时分析:
interface MyInterface { fun doSomething() val someProperty: String } fun analyzeInterface() { val kClass = MyInterface::class println("Interface ${kClass.qualifiedName}") println("Functions:") kClass.memberFunctions.forEach { fn -> println("- ${fn.name} with ${fn.parameters.size} parameters") } println("Properties:") kClass.memberProperties.forEach { prop -> println("- ${prop.name} of type ${prop.returnType}") } }元编程应用场景:
- 自动生成接口实现
- 运行时接口验证
- 动态代理创建
- 序列化/反序列化框架
16. Kotlin接口的跨平台应用
16.1 多平台项目中的接口
在Kotlin多平台项目中,接口是共享代码的核心工具:
// 公共模块 expect interface PlatformStorage { fun saveData(key: String, value: String) fun loadData(key: String): String? } // 平台特定实现 // JVM actual class JvmStorage : PlatformStorage { actual override fun saveData(key: String, value: String) { Files.writeString(Path.of(key), value) } actual override fun loadData(key: String): String? { return if (Files.exists(Path.of(key))) { Files.readString(Path.of(key)) } else null } } // JS actual class JsStorage : PlatformStorage { actual override fun saveData(key: String, value: String) { localStorage.setItem(key, value) } actual override fun loadData(key: String): String? { return localStorage.getItem(key) } }16.2 接口与Swift/Obj-C互操作
在Kotlin/Native中,接口可以暴露给Swift/Obj-C代码:
@ObjCName("DatabaseService") interface DatabaseService { @ObjCName("executeQuery") fun executeQuery(sql: String): ResultSet } class iOSDatabaseService : DatabaseService { override fun executeQuery(sql: String): ResultSet { // 实现 } }在Swift中可以直接使用:
let service: DatabaseService = iOSDatabaseService() let result = service.executeQuery(withSql: "SELECT * FROM users")17. Kotlin接口的版本兼容性策略
随着项目演进,接口可能需要变更,以下是保持兼容性的策略:
添加而非修改:
- 添加新方法时提供默认实现
- 避免修改现有方法签名
弃用而非删除:
interface MyInterface { @Deprecated("Use newMethod instead", ReplaceWith("newMethod()")) fun oldMethod() fun newMethod() { oldMethod() // 默认实现保持兼容 } }接口拆分: 当接口变得臃肿时,将其拆分为多个更专注的接口
版本化接口:
interface MyInterfaceV1 { fun methodV1() } interface MyInterfaceV2 : MyInterfaceV1 { fun methodV2() @Deprecated("Implemented in V1 interface") override fun methodV1() { // 默认实现 } }
18. Kotlin接口的测试策略
18.1 接口契约测试
确保所有实现类都遵守接口契约:
abstract class MyInterfaceContractTest { abstract fun createImplementation(): MyInterface @Test fun `should return non-null value`() { val impl = createImplementation() assertNotNull(impl.doSomething()) } @Test fun `should handle null input`() { val impl = createImplementation() assertDoesNotThrow { impl.handleInput(null) } } } class MyInterfaceImplTest : MyInterfaceContractTest() { override fun createImplementation() = MyInterfaceImpl() }18.2 默认方法测试
即使有默认实现,也应测试默认行为:
class MyInterfaceDefaultsTest { private val testImpl = object : MyInterface { // 仅实现抽象成员 override fun abstractMethod() = "test" } @Test fun `default method should return combined result`() { assertEquals("test-default", testImpl.combinedMethod()) } }18.3 模拟接口
使用MockK等框架模拟接口:
@Test fun `should call dependency`() { val mockDep = mockk<MyInterface>() every { mockDep.doSomething() } returns "mocked" val sut = SystemUnderTest(mockDep) sut.execute() verify { mockDep.doSomething() } }19. Kotlin接口的文档化
良好的文档对接口尤为重要,Kotlin的KDoc支持丰富的文档标记:
/** * 表示一个可以渲染的组件 * * 实现类必须确保: * - 线程安全 * - 支持多次渲染 * - 正确处理null属性 * * @see TextView 默认实现 * @sample com.example.RenderableSamples.basicUsage */ interface Renderable { /** * 将组件渲染到指定上下文 * @param context 渲染上下文,不能为null * @return 渲染是否成功 * @throws RenderException 当渲染失败时抛出 */ fun render(context: RenderContext): Boolean /** * 组件是否可见 * * 默认实现返回true,表示组件默认可见 */ val isVisible: Boolean get() = true }文档最佳实践:
- 描述接口的总体职责和契约
- 为每个成员提供详细文档
- 使用
@see引用相关类型 - 使用
@sample提供示例代码 - 记录线程安全要求
20. 从设计模式看Kotlin接口
20.1 工厂模式
interface Animal { fun speak(): String } class Dog : Animal { override fun speak() = "Woof!" } class Cat : Animal { override fun speak() = "Meow!" } interface AnimalFactory { fun createAnimal(type: String): Animal } class SimpleAnimalFactory : AnimalFactory { override fun createAnimal(type: String): Animal { return when (type.lowercase()) { "dog" -> Dog() "cat" -> Cat() else -> throw IllegalArgumentException("Unknown animal type") } } }20.2 观察者模式
interface EventListener { fun onEvent(event: Event) } class EventManager { private val listeners = mutableListOf<EventListener>() fun addListener(listener: EventListener) { listeners.add(listener) } fun notify(event: Event) { listeners.forEach { it.onEvent(event) } } } class Logger : EventListener { override fun onEvent(event: Event) { println("Event received: $event") } }20.3 策略模式
interface CompressionStrategy { fun compress(input: ByteArray): ByteArray } class ZipCompression : CompressionStrategy { override fun compress(input: ByteArray): ByteArray { // Zip实现 } } class GzipCompression : CompressionStrategy { override fun compress(input: ByteArray): ByteArray { // Gzip实现 } } class Compressor(private val strategy: CompressionStrategy) { fun compressData(data: ByteArray): ByteArray { return strategy.compress(data) } }21. Kotlin接口与Java互操作
21.1 从Java实现Kotlin接口
Kotlin接口可以无缝被Java实现:
// Kotlin接口 interface StringProcessor { fun process(input: String): String fun validate(input: String): Boolean { return input.isNotEmpty() } }// Java实现 public class JavaStringProcessor implements StringProcessor { @Override public String process(String input) { return input.toUpperCase(); } // 可以选择是否覆盖默认方法 }21.2 从Kotlin实现Java接口
Kotlin可以更简洁地实现Java接口:
// Java接口 public interface JavaCalculator { int add(int a, int b); default int square(int x) { return x * x; } }// Kotlin实现 object KotlinCalculator : JavaCalculator { override fun add(a: Int, b: Int) = a + b // 可以选择是否覆盖默认方法 }21.3 二进制兼容性注意事项
默认方法:
- Kotlin 1.4+与Java 8+的默认方法二进制兼容
- 旧版本可能需要
@JvmDefault注解
属性: Kotlin接口属性会编译为Java的getter/setter方法对
泛型差异: 注意Kotlin的声明处型变与Java通配符的映射关系
22. Kotlin接口与泛型
22.1 泛型接口基础
interface Repository<T> { fun getById(id: String): T? fun getAll(): List<T> fun save(entity: T) } class UserRepository : Repository<User> { private val store = mutableMapOf<String, User>() override fun getById(id: String): User? = store[id] override fun getAll(): List<User> = store.values.toList() override fun save(entity: User) { store[entity.id] = entity } }22.2 型变注解
Kotlin支持在接口上声明型变:
interface Producer<out T> { fun produce(): T } interface Consumer<in T> { fun consume(item: T) } // 使用 val stringProducer: Producer<String> = object : Producer<String> { override fun produce() = "Hello" } val anyProducer: Producer<Any> = stringProducer // 协变安全 val anyConsumer: Consumer<Any> = object : Consumer<Any> { override fun consume(item: Any) { println(item) } } val stringConsumer: Consumer<String> = anyConsumer // 逆变安全22.3 泛型约束
interface ComparableList<T : Comparable<T>> : List<T> { fun max(): T? fun min(): T? fun sort(): List<T> } class IntList : ComparableList<Int> { // 必须实现List<Int>和ComparableList<Int>的所有成员 }23. Kotlin接口与注解处理
接口常与注解处理器配合使用:
@Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.SOURCE) annotation class Factory(val type: KClass<*>) interface Animal { val name: String } @Factory(Dog::class) class Dog : Animal { override val name = "Dog" } @Factory(Cat::class) class Cat : Animal { override val name = "Cat" } // 注解处理器可以生成如下代码 object AnimalFactory { fun create(type: KClass<*>): Animal { return when (type) { Dog::class -> Dog() Cat::class -> Cat() else -> throw IllegalArgumentException("Unknown animal type") } } }24. Kotlin接口与编译器插件
高级开发者可以创建编译器插件来增强接口功能:
- 接口方法生成: 自动为接口生成