面试总结-Kotlin
Kotlin关键字 let、also、with、run、apply
let
- let也是我们用的最多的一个关键字,使用it代替对象,另外可以进行判空操作,当对象为空时,不会执行let函数体
also
类似let函数,但是返回值有区别:
- let函数:返回值 = 最后一行 / return的表达式
- also函数:返回值 = 传入的对象的本身
with
可以调用同一个对象的多个方法 / 属性,比如:
// 此处要调用people的name 和 age属性
// kotlin
val people = People("carson", 25)
with(people) {
println("my name is $name, I am $age years old")
}
run
结合了let、with两个函数的作用,即:
- 调用同一个对象的多个方法 / 属性时,可以省去对象名重复,直接调用方法名 / 属性即可
- 定义一个变量在特定作用域内
- 统一做判空处理
// 此处要调用people的name 和 age属性,且要判空
// kotlin
val people = People("carson", 25)
people?.run{
println("my name is $name, I am $age years old")
}
apply
与run函数类似,但区别在于返回值:
- run函数返回最后一行的值 / 表达式
- apply函数返回传入的对象的本身
Kotlin中的 inline, noinline, crossinline
class InlineMain {
companion object {
@JvmStatic
fun main(args: Array<String>) {
greeting {
println("After")
}
}
private fun greeting(after: () -> Unit) {
println("Hello")
after()
}
}
}
inline
如上代码,当我们用Android Studio字节码查看器查看生成的Java代码时,发现geeting会被创建一个临时对象来调用传入的方法,如果只是调用一两次是没有什么影响的,但是若是在高频使用场景下,方法可能会被调用100次,1000次,这样就会有成千上万个临时对象被创建。这在内存分配和虚拟机调用上都会加大运行时间开销。为了解决高阶函数所带来的额外开销,kotlin加入了inline关键字。
noinline
inline作用于函数,noinline作用于函数类型参数。inline代表整个函数内联,noinline则代表该函数类型参数不参与内联。
在某些场景下,我们并不希望所有的函数类型参数都被内联,也就是当我们需要在函数内将函数类型参数作为对象操作时,用noinline
修饰即可。
crossinline
noinline解决的是内联函数中的函数类型参数无法当作对象操作的问题,crossinline是解决内联函数中函数类型参数无法被间接调用以及非局部返回的问题。
Kotlin 中注解 @JvmOverloads的作用?
在 Kotlin 中,@JvmOverloads
是一个用于在 Java 代码中使用 Kotlin 方法的注解。它的作用是生成多个重载方法,以方便 Java 代码调用 Kotlin 方法。
具体来说,当在 Kotlin 中的一个方法中使用 @JvmOverloads
注解时,编译器会根据该方法的参数列表生成多个重载方法,每个重载方法都省略了最后一个参数,依次减少参数直到不包含任何参数。这样一来,当在 Java 代码中调用这个方法时,可以根据需要选择不同数量的参数。
Kotlin相对java的区别和优势
1. 简洁性和可读性:
- Kotlin 相对于 Java 更简洁,减少了代码量,提高了代码的可读性和可维护性。例如,Kotlin 的空安全机制可以避免空指针异常,减少了对 null 的处理。
- Kotlin 提供了更简洁的语法和更少的样板代码,例如通过类型推断、扩展函数、Lambda 表达式等特性来简化代码。
2. 安全性和可靠性:
- Kotlin 在设计上考虑了一些 Java 中的安全性和可靠性问题,并提供了一些语言特性来解决这些问题。例如,Kotlin 的空安全机制可以避免空指针异常,类型系统可以减少类型转换错误。
- Kotlin 支持不变性和可变性的区分,通过
val
和var
关键字来声明变量,避免了一些不必要的变量状态变化。
3. 函数式编程支持:
- Kotlin 对函数式编程提供了良好的支持,包括 Lambda 表达式、高阶函数、函数合成等特性,可以编写更简洁、更函数式的代码。
- Kotlin 的集合操作符和扩展函数使得对集合的处理更加方便和简洁,例如
map
、filter
、reduce
等操作。
4. 互操作性:
- Kotlin 兼容 Java 并且可以与 Java 代码无缝地互操作,可以直接调用 Java 类和库,并且可以与现有的 Java 项目无缝集成,逐步迁移到 Kotlin。
- Kotlin 提供了一些工具和插件来简化 Kotlin 和 Java 之间的互操作性,例如 Kotlin 和 Java 代码的自动转换工具。
5. 工具和生态系统:
- Kotlin 受到 Google 官方支持,并且在 Android 开发领域得到了广泛应用,是一种非常适合 Android 开发的语言。
6. 其他特性:
- Kotlin 还提供了一些其他的语言特性,如拓展函数、数据类、密封类、对象表达式等,可以更方便地实现一些常见的编程模式和功能。
Kotlin为什么要出协程,它和java线程有什么区别
Kotlin 引入协程的主要原因是为了简化并发编程,并提供一种更加轻量级、灵活和可控的并发处理方式。协程是一种并发设计模式,它允许在程序中的某个地方挂起执行,稍后再恢复执行,而不会阻塞整个线程。
Kotlin协程
协程引入:
- 协程可以让异步代码同步化,降低程序涉及的复杂度
- 协程本质是轻量级线程,单个线程可以运行多个协程,协程的运行不会导致线程阻塞
协程启动:
- 协程启动需要三部分:上下文、启动模式、协程体。创建协程的方式有runBlocking、launch和async,推荐使用CoroutineScope.launch的方式创建协程,使用async的方式创建并发执行,同步等待获取返回值的情况。
- Job是launch构建协程返回的一个协程任务,完成时没有返回值,可看成协程对象本身。其提供相关方法可用于观察协程执行情况。Deferred继承自Job,是async构建协程返回的一个协程任务,可通过调用await()方法等待执行完成获取结果。
- 启动协程需要作用域,作用域在协程创建过程中产生,常见的协程作用域有GlobalScope、coroutineScope等,协程配合Jetpack Lifecycle相关组件提供的lifecycleScope等作用域进行使用,异常丝滑好用。
- 协程的启动模式有DEFAULT、ATOMIC、UNDISPATCHED、LAZY四种,注意不同启动模式的区别。
- 如果要在父协程中进行子协程切换操作,可以使用withContext。
协程调度:
- 协程上下文是一个元素的集合,其定义是递归的,自己包含若干个自己,其结构介于set 和 map 之间。
- 协程实现的本质是回调,这个回调即Continuation。协程拦截器的实现就是拦截Continuation,可在此处进行缓存、日志打印等拦截处理。
- 调度器即确认相关协程在哪个线程上执行,调度的本质是解决挂起恢复后协程逻辑在哪里运行的问题,其继承自拦截器。
- 调度器的是实现原理即在协程启动时通过拦截器进行拦截,返回一个Continuation,再在协程恢复进行resumeWith操作时,进行线程切换判断和线程切换。
协程挂起:
- 挂起函数是一个可启动、暂停和恢复的函数,被suspend修饰的函数在协程运行时不是一定会被挂起的。
- 挂起函数的挂起实现原理就是状态机的状态转移。协程体的执行就是一个状态机,每遇到一次挂起函数就是一次状态转移,而协程的恢复不过是从一种状态跳转到下一种状态。挂起函数将整个执行过程划分为多个Continuation片段,利用状态机的方式保证各个片段时顺序执行的,从而实现了用顺序的代码实现异步逻辑。