Kotlin和Java本质上都是使用的Java字节码,如下图所示:
以下内容节选本文
编译主要分为四个过程:
词法分析
其实词法分析就是将源程序读入的字符序列,按照一定的规则转换成词法单元(Token)序列的过程。词法单元是语言中具有独立意义的最小单元,包括关键字、标识符、常数、运算符、界符等等。
语法分析
语法分析的过程是建立在词法分析的基础上,将单词(Token)序列组合成各类语法短语,如“程序”,“语句”,“表达式”等等,语法分析器将判断源程序在结构上是否正确。
KotlinParser 语法分析器调用 KotlinParsing 进行语法分析,并生成AST抽象语法树。关于如何生成一个简单表达式的AST树,可以参考下图:
Kotlin 的接口,跟 Java 最大的差异就在于,接口的方法可以有默认实现,同时,它也可以有属性。
Kotlin 当中的普通嵌套类,它的本质是静态的。相应地,如果想在 Kotlin 当中定义一个普通的内部类,我们需要在嵌套类的前面加上 inner 关键字。
定义密封类需要使用 sealed 关键字,它的中文含义也代表着“密封”。在 Android 开发当中,我们会经常使用密封类对数据进行封装。比如我们可以来看一个代码例子:
sealed class Result<out R> {
data class Success<out T>(val data: T, val message: String = "") : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
data class Loading(val time: Long = System.currentTimeMillis()) : Result<Nothing>()
}
首先 object 定义的匿名内部类。object 关键字定义单例类的时候,Kotlin 编译器会将其转换成静态代码块的单例模式。
companion object半生对象:是 Java 中的 static 变量,只能定义在对应的类中。
模板单例:
abstract class BaseSingleton<in P,out T> {
@Volatile
private var instance: T? = null
protected abstract fun creator(param: P): T
fun getInstance(param: P): T = instance ?: synchronized(this) {
instance ?: creator(param).also { instance = it }
}
}
Kotlin 的扩展,由于它本质上并没有修改接收类型的源代码,所以它的行为是无法与“类成员”完全一致的。那么它对比普通的类成员,就会有以下几个限制。
Lambda表达式
SAM 代表着只有一个抽象方法的接口
内联函数的工作原理很简单,就是 Kotlin 编译器会将内联函数中的代码在编译的时候自动替换到调用它的地方,这样也就不存在运行时的开销了。
大神的讲解
比较全面的讲解
系列讲解
协程之所以是非阻塞,是因为它支持“挂起和恢复”;而挂起和恢复的能力,主要是源自于“挂起函数”;而挂起函数是由 CPS 实现的,其中的 Continuation,本质上就是 Callback。
fun main() {
GlobalScope.launch(context = Dispatchers.IO) {
//延时一秒
delay(1000)
log("launch")
}
//主动休眠两秒,防止 JVM 过快退出
Thread.sleep(2000)
log("end")
}
private fun log(msg: Any?) = println("[${Thread.currentThread().name}] $msg")
[DefaultDispatcher-worker-1] launch
[main] end
上边代码,通过 GlobalScope(全局作用域)启动了一个协程,从输出结果可以看出来,启动的协程是运行在协程内部的线程池中。
@DelicateCoroutinesApi
public object GlobalScope : CoroutineScope {
/**
* Returns [EmptyCoroutineContext].
*/
override val coroutineContext: CoroutineContext
get() = EmptyCoroutineContext
}
CoroutineScope
协程作用域,GlobalScope 是 CoroutineScope 的一个实现类,用于指定协程的作用范围,可用于管理多个协程的生命周期,所有协程都需要通过 CoroutineScope 来启动。
CoroutineContext
协程上下文,包含多种类型的配置参数。Dispatchers.IO 就是 CoroutineContext 这个抽象概念的一种实现,用于指定协程的运行载体,即用于指定协程要运行在哪类线程上
挂起协程之所以是非阻塞,是因为它支持“挂起和恢复”;而挂起和恢复的能力,主要是源自于“挂起函数”;挂起函数,只能在协程作用域当中被调用,或者是被其他挂起函数调用。
挂起,只是将程序执行流程转移到了其他线程,主线程并未被阻塞。
挂起函数是由 CPS 实现的,其中的 Continuation,本质上就是 Callback。
https://juejin.cn/post/6844904101801639949
https://juejin.cn/post/7040001489904861191
背压
https://juejin.cn/post/7088338829316210702
https://juejin.cn/post/6844904102040698893
https://blog.csdn.net/gongjdde/article/details/124001671