Kotlin 扩展函数和属性
扩展函数基础
概念和用途
-
定义
- 在不修改原类的情况下为类添加新的功能
- 可以为任何类(包括第三方库的类)添加扩展函数
- 扩展函数在编译时被解析为静态方法
-
语法特点
- 使用
fun关键字定义 - 接收者类型位于函数名前
- 在函数体内可以通过
this访问接收者对象
- 使用
常见面试题
-
扩展函数和成员函数的区别是什么?
答案: - 扩展函数在编译时被解析为静态方法,而成员函数是类的一部分 - 扩展函数不能访问私有成员,而成员函数可以 - 扩展函数的调用取决于变量的静态类型,而成员函数取决于实际类型 -
为什么需要扩展函数?
答案: - 增加代码的可读性和可维护性 - 避免创建包装类 - 方便对现有类库进行功能扩展 - 保持代码的整洁和模块化
扩展属性
基本概念
-
特点
- 不能有初始化器
- 必须显式提供 getter/setter
- 不能有幕后字段(backing field)
-
使用场景
- 计算属性
- 缓存值
- 提供便捷访问方式
实战示例
-
字符串扩展
val String.lastChar: Char get() = this[length - 1] val String.isEmail: Boolean get() = matches(Regex("^[A-Za-z0-9+_.-]+@(.+)$")) -
集合扩展
val <T> List<T>.secondOrNull: T? get() = if (size >= 2) this[1] else null
作用域和可见性
-
扩展的可见性
- 遵循普通声明的可见性规则
- 可以在顶层声明
- 可以在类内部声明
-
命名冲突解决
- 成员函数优先于扩展函数
- 可以使用完全限定名解决冲突
面试考点
-
扩展函数的调用优先级
问:如果有同名的成员函数和扩展函数,会调用哪个? 答: - 成员函数优先级高于扩展函数 - 如果需要强制调用扩展函数,需要使用完全限定名 -
扩展函数的性能影响
问:使用扩展函数会影响性能吗? 答: - 扩展函数在编译时会被转换为静态方法 - 不会产生额外的运行时开销 - 不会创建新的类或对象
最佳实践
-
使用建议
- 保持扩展函数的纯函数特性
- 避免过度使用扩展函数
- 合理组织扩展函数的包结构
- 提供清晰的文档注释
-
常见陷阱
- 注意空安全处理
- 避免命名冲突
- 注意扩展函数的可见性
- 不要滥用扩展函数
总结
-
核心优势
- 提高代码可读性
- 增强现有类的功能
- 保持代码整洁
- 便于单元测试
-
使用场景
- 工具类函数
- UI组件扩展
- 集合操作扩展
- 字符串处理