Kotlin学习笔记
1.如果构造函数有注解或可见性修饰符,这个 constructor 关键字是必需的,并且这些修饰符在它前面:
class Customer public @Inject constructor(name: String) { /*……*/ }
2.要创建一个类的实例,我们就像普通函数一样调用构造函数:Kotlin 并没有 new 关键字
val invoice = Invoice()
val customer = Customer("Joe Smith")
3.如果派生类有一个主构造函数,其基类可以(并且必须) 用派生类主构造函数的参数就地初始化。
如果派生类没有主构造函数,那么每个次构造函数必须使用 super 关键字初始化其基类型,或委托给另一个构造函数做到这一点。 注意,在这种情况下,不同的次构造函数可以调用基类型的不同的构造函数:
class MyView : View {
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}
4.只有一个抽象方法的接口称为函数式接口或 SAM(单一抽象方法)接口。函数式接口可以有多个非抽象成员,但只能有一个抽象成员。
可以用 fun 修饰符在 Kotlin 中声明一个函数式接口。
fun interface KRunnable {
fun invoke()
}
5.局部变量、函数和类不能有可见性修饰符。
6.数据类必须满足以下要求:
主构造函数需要至少有一个参数;
主构造函数的所有参数需要标记为 val 或 var;
数据类不能是抽象、开放、密封或者内部的;
(在1.1之前)数据类只能实现接口。
7.解构声明
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age") // 输出 "Jane, 35 years of age"
8.密封类sealed 密封类不允许有非-private 构造函数(其构造函数默认为 private)使用密封类的关键好处在于使用 when 表达式 的时候,如果能够验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了。
9.标记为 inner 的嵌套类能够访问其外部类的成员。内部类会带有一个对外部类的对象的引用:
class Outer {
private val bar: Int = 1
inner class Inner {
fun foo() = bar
}
}
val demo = Outer().Inner().foo() // == 1
10.使用对象表达式创建匿名内部类实例:
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { …… }
override fun mouseEntered(e: MouseEvent) { …… }
})
11.inline内联类必须含有唯一的一个属性在主构造函数中初始化。在运行时,将使用这个唯一属性来表示内联类的实例(类似于java中的static静态类)
12.高阶函数是将函数用作参数或返回值的函数
13本质上,协程是轻量级的线程。 它们在某些 CoroutineScope 上下文中与 launch 协程构建器 一起启动。 这里我们在 GlobalScope 中启动了一个新的协程,这意味着新协程的生命周期只受整个应用程序的生命周期限制。
import kotlinx.coroutines.*
fun main() {
GlobalScope.launch { // 在后台启动一个新的协程并继续
delay(1000L) // 非阻塞的等待 1 秒钟(默认时间单位是毫秒)
println("World!") // 在延迟后打印输出
}
println("Hello,") // 协程已在等待时主线程还在继续
Thread.sleep(2000L) // 阻塞主线程 2 秒钟来保证 JVM 存活
}
可以将 GlobalScope.launch { …… } 替换为 thread { …… },并将 delay(……) 替换为 Thread.sleep(……) 达到同样目的
调用了 runBlocking 的主线程会一直 阻塞 直到 runBlocking 内部的协程执行完毕。
这里的 runBlocking { …… } 作为用来启动顶层主协程的适配器。 我们显式指定了其返回类型 Unit,因为在 Kotlin 中 main 函数必须返回 Unit 类型。
import kotlinx.coroutines.*
fun main() = runBlocking<Unit> { // 开始执行主协程
GlobalScope.launch { // 在后台启动一个新的协程并继续
delay(1000L)
println("World!")
}
println("Hello,") // 主协程在这里会立即执行
delay(2000L) // 延迟 2 秒来保证 JVM 存活
}
延迟一段时间来等待另一个协程运行并不是一个好的选择。让我们显式(以非阻塞方式)等待所启动的后台 Job 执行结束:
val job = GlobalScope.launch { // 启动一个新协程并保持对这个作业的引用
delay(1000L)
println("World!")//子协程
}
println("Hello,")
job.join() // 等待直到子协程执行结束
15.runBlocking 与 coroutineScope 可能看起来很类似,因为它们都会等待其协程体以及所有子协程结束。 主要区别在于,runBlocking 方法会阻塞当前线程来等待, 而 coroutineScope 只是挂起,会释放底层线程用于其他用途。 由于存在这点差异,runBlocking 是常规函数,而 coroutineScope 是挂起函数。
import kotlinx.coroutines.*
fun main() = runBlocking { // this: CoroutineScope
launch {
delay(200L)
println("Task from runBlocking")
}
coroutineScope { // 创建一个协程作用域
launch {
delay(500L)
println("Task from nested launch")
}
delay(100L)
println("Task from coroutine scope") // 这一行会在内嵌 launch 之前输出
}
println("Coroutine scope is over") // 这一行在内嵌 launch 执行完毕后才输出
}
16.使用async并发
async 就类似于 launch。它启动了一个单独的协程,这是一个轻量级的线程并与其它所有的协程一起并发的工作。不同之处在于 launch 返回一个 Job 并且不附带任何结果值,而 async 返回一个 Deferred —— 一个轻量级的非阻塞 future, 这代表了一个将会在稍后提供结果的 promise。你可以使用 .await() 在一个延期的值上得到它的最终结果, 但是 Deferred 也是一个 Job,所以如果需要的话,你可以取消它
17.data 数据类的== 比较的是值,普通类比较的是引用
更多推荐

所有评论(0)