Kotlin学习笔记三

210 阅读3分钟

委托类

存在接口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())
}