尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Kotlin接口全面解析:从基础到高级应用

Kotlin接口全面解析:从基础到高级应用 1. Kotlin接口基础概念解析Kotlin接口是一种定义行为契约的强大工具它允许我们声明一组抽象方法和属性而无需关心具体实现。与Java接口相比Kotlin接口具有更丰富的特性这也是为什么它成为现代Kotlin开发中不可或缺的部分。1.1 接口的本质与作用接口在Kotlin中通过interface关键字定义它本质上是一组抽象成员的集合。与抽象类不同接口不能保存状态尽管可以通过属性访问器实现类似功能这使得它成为定义纯行为的理想选择。接口的核心价值体现在三个方面多继承支持Kotlin类可以实现多个接口解决了单继承语言的局限性契约式编程明确规定了实现类必须提供哪些功能解耦将定义与实现分离提高代码的灵活性和可维护性interface Clickable { fun click() fun showOff() println(Im 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简称SAMKotlin提供了特殊的语法糖允许使用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(Im 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() { superA.foo() // 明确调用A的实现 superB.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 OnItemClickListenerT { fun onItemClick(item: T, position: Int) } class MyAdapterT( private val items: ListT, private val listener: OnItemClickListenerT ) : RecyclerView.AdapterMyViewHolderT() { override fun onBindViewHolder(holder: MyViewHolderT, position: Int) { holder.bind(items[position]) holder.itemView.setOnClickListener { listener.onItemClick(items[position], position) } } } // 使用 adapter MyAdapter(dataList, object : OnItemClickListenerData { override fun onItemClick(item: Data, position: Int) { // 处理点击 } })6.2 ViewModel与UI通信interface LoginViewModel { val state: LiveDataLoginState 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(): ListNews suspend fun fetchNewsDetail(id: String): NewsDetail } class NewsRepositoryImpl( private val api: NewsApi, private val db: NewsDatabase ) : NewsRepository { override suspend fun fetchLatestNews(): ListNews { return try { val news api.getLatestNews() db.saveNews(news) news } catch (e: Exception) { db.getCachedNews() } } // ...其他实现 }7.2 Flow在接口中的应用interface StockPriceMonitor { fun monitorStock(symbol: String): FlowPriceUpdate suspend fun getCurrentPrice(symbol: String): PriceUpdate } class RealStockPriceMonitor( private val stockService: StockService ) : StockPriceMonitor { override fun monitorStock(symbol: String): FlowPriceUpdate { 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 ItemClickListenerT (T, Int) - Unit interface AdapterT { var itemClick: ItemClickListenerT } class MyAdapterT : AdapterT { override var itemClick: ItemClickListenerT { _, _ - } }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 Resultout T { data class Successout T(val value: T) : ResultT data class Error(val exception: Throwable) : ResultNothing } fun handleResult(result: ResultString) { when(result) { is Result.Success - println(result.value) is Result.Error - println(Error: ${result.exception}) } }11.2 高阶函数与接口interface TransformerT, R { fun transform(input: T): R } fun T, R ListT.map(transformer: TransformerT, R): ListR { return this.map { transformer.transform(it) } } // 使用 val stringToLength object : TransformerString, Int { override fun transform(input: String) input.length } val lengths listOf(a, ab, abc).map(stringToLength)11.3 函数式模式实现Monad模式示例interface Monadout T { fun R flatMap(f: (T) - MonadR): MonadR } class Maybeout T(val value: T?) : MonadT { override fun R flatMap(f: (T) - MonadR): MonadR { 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 mutableListOfString() 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 { singleDatabaseService { ProductionDatabaseService() } } // 使用 class UserRepository(private val db: DatabaseService) { fun getUsers(): ListUser { val result db.executeQuery(SELECT * FROM users) // 处理结果 } }13.2 接口与测试替身接口使得创建测试替身(Test Double)变得简单class TestDatabaseService : DatabaseService { private val data mutableMapOfString, ListMapString, Any() fun addTestData(table: String, rows: ListMapString, 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 mockkMyInterface() 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 mutableListOfEventListener() 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 RepositoryT { fun getById(id: String): T? fun getAll(): ListT fun save(entity: T) } class UserRepository : RepositoryUser { private val store mutableMapOfString, User() override fun getById(id: String): User? store[id] override fun getAll(): ListUser store.values.toList() override fun save(entity: User) { store[entity.id] entity } }22.2 型变注解Kotlin支持在接口上声明型变interface Producerout T { fun produce(): T } interface Consumerin T { fun consume(item: T) } // 使用 val stringProducer: ProducerString object : ProducerString { override fun produce() Hello } val anyProducer: ProducerAny stringProducer // 协变安全 val anyConsumer: ConsumerAny object : ConsumerAny { override fun consume(item: Any) { println(item) } } val stringConsumer: ConsumerString anyConsumer // 逆变安全22.3 泛型约束interface ComparableListT : ComparableT : ListT { fun max(): T? fun min(): T? fun sort(): ListT } class IntList : ComparableListInt { // 必须实现ListInt和ComparableListInt的所有成员 }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接口与编译器插件高级开发者可以创建编译器插件来增强接口功能接口方法生成 自动为接口生成
返回列表