Android面试笔记-kotlin相关
1. kotlin相对于Java的优
kotlin是一种比较现代化的语言,融合了多种语言的优势。比如使用JVM的内存管理,空安全控制,lambda表达式,以及其他各种语法糖。
- 语法简洁,减少样板代码
- 空安全(Null Safety)
- 扩展函数(Extension Functions)
- 函数式编程支持,Lambda 和 高阶函数
- 协程(Coroutines)
- 智能类型转换(Smart Casts),is判断后屋再次强转
- 默认参数与命名参数,减少方法重载
- 与 Java 的完全互操作性
- 现代语言特性,自动拆解、内联函数、密封类
- Google官方支持与社区生态
2.高阶函数
高阶函数是可以接收函数作为参数 或返回函数作为结果的函数
- 函数类型的引用
- Lambda表达式定义匿名函数
- 函数引用,::+函数名,传递函数引用
- 内联函数
- 标准库高阶函数操作符
3.内联函数
内联函数(Inline Functions) 是一种通过 inline
关键字修饰的函数,主要用于优化高阶函数(尤其是包含 Lambda 参数的函数)的性能。它的核心原理是在编译时将函数体直接插入到调用处,从而减少函数调用和 Lambda 表达式带来的额外开销。
适用场景
- 高阶函数:当函数参数是 Lambda 时,内联可以避免创建匿名类对象(减少内存开销)。
- 性能敏感代码:例如频繁调用的工具函数。
- 结合
reified
类型参数:在泛型中保留类型信息
注意事项
- 代码膨胀:内联函数会导致函数体被复制到多个调用处,如果函数体较大或调用频繁,可能增加生成的字节码大小。应避免内联大型函数。
- 限制:内联函数不能直接访问外层类的私有成员,部分操作(如递归调用)无法内联
noinline
内联函数的某个参数是函数,则该参数默认也是 inline 的,当需要禁止这个函数参数inline,比如需要被其他非inline函数调用或者返回值,就需要使用noinline
标记。
crossinline
在内联函数中的 lambda 表达式参数,可以直接使用不带标签的 return,返回的是调用内联函数的外部函数,而不是内联函数本身,默认就是非局部返回。 crossinline
标记禁止内联函数的 lambda 表达式参数使用非局部返回,即禁用return
4.扩展函数
原理:扩展函数在编译时会被转换为静态方法,接收者对象(即扩展的目标类实例)作为该静态方法的第一个参数。
- 无法访问私有成员
- 静态解析(非多态) :扩展函数的调用在编译时根据接收者的声明类型确定,而非运行时实际类型
kotlin
open class Parent
class Child : Parent()
fun Parent.foo() = "Parent"
fun Child.foo() = "Child"
val obj: Parent = Child()
println(obj.foo()) // 输出 "Parent",而非 "Child"
- 优先级低于成员方法
- 扩展属性实现,扩展属性同样通过静态方法实现,但不会有实际字段存储,必须通过
getter
(和setter
,若为var
) - 可空接收者支持
- 扩展函数需通过导入(
import
)才能使用,若存在同名冲突,需使用全限定名或别名
5.标准库中的作用域函数
Kotlin 标准库中的这些作用域函数(let
, also
, run
, with
, apply
, repeat
)在对象操作和代码块执行中有不同的用途和特点。它们的核心区别在于 上下文对象的引用方式 和 返回值类型
let
-
上下文对象 :通过
it
引用。 -
返回值:Lambda 表达式的结果(最后一行)。
-
使用场景 :
- 处理可空对象(避免空指针)。
- 链式调用中转换或处理对象。
-
示例 :
kotlinval length = text?.let { println("Processing: $it") it.length // 返回长度 } ?: 0
also
-
上下文对象 :通过
it
引用。 -
返回值 :返回对象本身(
this
)。 -
使用场景 :
- 链式调用中执行副作用操作(如日志、修改对象属性)。
-
示例 :
kotlinval list = mutableListOf(1, 2, 3).also { println("Initial list: $it") it.add(4) // 修改对象 }
run
-
上下文对象 :通过
this
引用(可省略)。 -
返回值:Lambda 表达式的结果。
-
变体 :
- 扩展函数形式 :
obj.run { ... }
- 非扩展函数形式 :
run { ... }
(无上下文对象)。
- 扩展函数形式 :
-
使用场景 :
- 初始化对象并计算结果。
- 替代
let
但需要省略it
。
-
示例 :
kotlinval result = Person().run { name = "Alice" // 直接访问属性(this 可省略) age = 30 getInfo() // 返回结果 }
with
-
上下文对象 :通过
this
引用(参数传入)。 -
返回值:Lambda 表达式的结果。
-
特点:非扩展函数,直接传入对象。
-
使用场景 :
- 对对象进行多次操作,无需返回对象本身。
-
示例 :
kotlinval person = Person("Bob", 25) val info = with(person) { age += 1 // 修改属性 "Name: $name, Age: $age" // 返回结果 }
apply
-
上下文对象 :通过
this
引用。 -
返回值 :返回对象本身(
this
)。 -
使用场景 :
- 对象初始化(如配置属性)。
-
示例 :
kotlinval person = Person().apply { name = "Charlie" age = 40 // 返回 this(Person 对象) }
repeat
-
用途:重复执行代码块指定次数。
-
返回值 :
Unit
(无返回值)。 -
使用场景 :
- 替代简单的
for
循环。
- 替代简单的
-
示例 :
kotlinrepeat(3) { i -> println("Iteration $i") }
对比表格
函数 | 上下文对象 | 返回值 | 扩展函数 | 典型场景 |
---|---|---|---|---|
let |
it |
Lambda 结果 | 是 | 处理可空对象、链式转换 |
also |
it |
对象本身 | 是 | 链式副作用操作 |
run |
this |
Lambda 结果 | 是/否 | 初始化对象并计算、替代 let |
with |
this |
Lambda 结果 | 否 | 对已有对象进行多次操作 |
apply |
this |
对象本身 | 是 | 对象初始化配置 |
repeat |
无 | Unit |
否 | 替代简单循环 |
选择指南
- 需要返回对象本身 →
apply
或also
。- 用
apply
配置属性(this
可省略)。 - 用
also
执行副作用(如日志)。
- 用
- 需要返回计算结果 →
let
、run
或with
。- 处理可空对象 →
let
。 - 需要
this
上下文 →run
或with
。
- 处理可空对象 →
- 重复执行代码块指定次数 →
repeat
。