委托类
存在接口A,B和C都实现A接口,C将B作为构造参数并且设置委托。调用C实例所有接口A方法都会自动个调用实例B方法。
interface A {
fun a()
fun b()
}
class B : A {
override fun a() { println("B-a") }
override fun b() { println("B-b") }
}
class C(a: A) : A by a {
override fun b() { println("C-b") }
}
C(B()).a() // B-a
C(B()).b() // C-b
委托属性
将一个属性的具体实现委托给另外一个类实现。
class MyClass {
var p by Delegate()
}
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}
委托属性实现延迟加载
// Later.kt
class Later<T>(val block: () -> T) {
var value: Any? = null
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
if (value == null) { value = block() }
return value as T
}
}
fun <T> later(block: () -> T) = Later(block)
fun main() {
val str:String by later {
println("create")
"aaa"
}
println("str next")
println("str = $str")
}
// str next
// create
// str = aaa
泛型实化
inline fun <reified T> getType() = T::class.java
fun main() {
println("string getType = ${getType<String>()}")
println("Int getType = ${getType<Int>()}")
}
泛型实化应用
// reified.kt
inline fun <reified T : Activity> startActivity(context: Context, block: Intent.() -> Unit) {
val intent = Intent(context, T::class.java)
intent.block()
context.startActivity(intent)
}
泛型协变和逆变
in和out位置说明。in是在参数位置,属于输入;out是在返回位置,属于输出。
interface MyClass<T> {
// 参数输入为in,参数返回为out
// in out
fun method(t: T): T
}
协变
使用out关键字定义泛型协变,指定协变后泛型T只能出现在输出位置。如明确代码没有错误,使用@UnsafeVariance注释即可出现在in位置。
// 协变
class TestOut<out T>(private val data: T?) {
// 使用@UnsafeVariance可以破坏协变规则
fun eq(t: @UnsafeVariance T): Boolean {
data == t
}
fun get(): T? {
return data
}
}
逆变
逆变可以看成是协变反过来
使用in关键字定义泛型逆变,指定逆变后泛型T只能出现在输入(in)位置。如明确代码没有错误,使用@UnsafeVariance注释即可出现在输出(out)位置。
// 逆变
interface Transform<in T> {
fun transform(t: T): String
// 使用@UnsafeVariance可以破坏逆变规则
fun transform(name: String): @UnsafeVariance T
}
协程
1. GlobalScope.launch {}
// 创建顶层协程 不阻塞
GlobalScope.launch {
delay(randomLong())
println("GlobalScope.launch")
}
2. runBlocking {}
// 在主线程中使用会阻塞主线程,不建议
// 协程作用域 阻塞线程,等待里面协程和子协程全部运行完毕
runBlocking {
delay(randomLong())
println("runBlocking")
}
3. launch 在协程环境中使用,开启子协程
runBlocking {
// 子协程 只能在协程作用域中使用
launch {
delay(randomLong())
println("launch")
}
}
4. coroutineScope.launch {} (推荐)
// 在项目中实际使用,job可以统一取消协程
val job = Job()
val coroutineScope = CoroutineScope(job)
coroutineScope.launch {
println("job coroutineScope launch before")
delay(randomLong())
println("job coroutineScope launch after")
}
job.cancel()
5. async 返回子协程结果
runBlocking {
// async 创建新的子协程并返回Deferred对象,可以调用 Deferred.await() 阻塞当前线程等待返回结果。
val deferred1 = async {
delay(100)
"async1"
}
val deferred2 = async {
delay(50)
"async2"
}
println("async1 = ${deferred1.await()}, async2 = ${deferred2.await()}")
}
6. suspend 和 corroutineScope 挂起函数修饰
提供方法修饰,表明与协程中调用,可以在代码块中使用协程上下文
// 使用 suspend 修饰的方法可以使用 delay() 函数,只能被协程调用
suspend fun useDelay() {
delay(randomLong())
}
// 使用 suspend 修饰的方法可以使用 delay() 函数,只能被协程调用
suspend fun useCoroutineScope() = coroutineScope {
// 使用 coroutineScope 函数可以在规定在协程上下文
launch {
delay(randomLong())
println("coroutineScope launch")
}
delay(randomLong())
}