笔记整理

kotlin中inline,noinline,crossinline区别?

  1. 默认函数中如果没加inline,那就是非内联函数,此时lambda会生成一个新的类,该类是继承自Lambda抽象类,并实现了Function接口,其中invoke方法就是Function接口的方法,invoke中的方法就是lambda代码块的代码。
  2. 内联函数(加inline关键字)的lambda如果没加noinline或crossinline,默认会把lambda的代码块给平铺到调用处,所以此时如果在lambda中加return的话,会直接不执行外层函数后续代码。如果是非内联函数的话,由于它是生成一个单独的类,不存在平铺代码,所以return是编译不过去的。
  3. noinline和inline是对立关系,它是将lambda不内联处理,如果你需要对该lambda作为对象来使用的时候,此时需要用到noinline,如果一个内联函数都是noinline的lambda表达式,那么此时as会提示你此处可以去掉inline关键字了,当做普通的高阶函数来处理就行。
  4. crossinline算是在内联和非内联之间做智能化选择,如果你将lambda表达式当做变量来使用,此时编译器不会内联该lambda,比如:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
inline fun hello4(run1: () -> Unit, crossinline run: () -> Unit) {
    run1()
    hello5 {
        run()
    }
    println("hello4后续代码")
}
fun hello5(run: () -> Unit) {
    run()
    println("hello5后续代码")
}

上面我将hello4中的run表达式传给了hello5,而hello5不是一个内联函数,所以此时会把lambda作为一个变量传到hello5中: crossinline将lambda当做变量使用

如果改成如下方式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
inline fun hello4(run1: () -> Unit, crossinline run: () -> Unit) {
    run1()
    hello5 {
        run()
    }
    println("hello4后续代码")
}
inline fun hello5(run: () -> Unit) {
    run()
    println("hello5后续代码")
}

crossinline将lambda内联 相关文档:https://juejin.cn/post/6869954460634841101

java lambda和kotlin lambda区别

  1. 在java中如果使用匿名内部类的形式,在编译时它是会单独生成一个类,其中类名是「外部类名$index.class」这种形式。如果使用lambda的形式,它不会在编译时单独生成一个类,它是执行了invokedynamic指令,在运行时动态生成lambda的类,其中类名是「外部类名$Lambda$index.class」这种形式。 参考:https://juejin.cn/post/7004642395060961310
  2. kotlin lambda它是在编译时看是否需要生成单独的类,如果是内联的时候就直接平铺代码,如果是非内联的时候才生成单独的类。

协程是怎么挂起的?怎么恢复的?

  1. 首先每一个协程代码块都会被编译成SuspendLambda对象,它也是一个Continuation对象,每次在执行到SuspendLambda的resume时候,都会去执行invokeSuspend方法,而该方法里面会去执行子协程,如果子协程返回SUSPEND_COROUTINE状态的时候,父协程的resume方法会直接return了。当子协程执行完后,会通知父协程,此时父协程的的invokeSuspend方法再次被执行,而此时的状态机会发生变化,如果此时状态恢复后,会执行父协程中的Continuation,也就是父父协程的执行。

协程中的dispather是怎么指定在哪个线程上执行的?

首先dispather它是CoroutineContext(上下文)的一部分,在协程启动过程中,会取CoroutineContext中的CoroutineDispathcer部分。此时会构造一个DispathedContinuation对象,并把前面取到的Dispather传到DispathedContinuation中,此时会将DispathedContinuation扔到线程池中,最终会执行DispathedContinuation的run方法,在run里面会执行到SuspendLambda,也就是协程的代码块,最终会执行它的invokeSuspend方法。所以协程代码块中代码要执行在哪个线程是协程上下文的dispather部分指定的线程。 相关文档:https://www.xiangcman.fun/p/%E5%8D%8F%E7%A8%8B%E5%A6%82%E4%BD%95%E5%88%87%E6%8D%A2%E7%BA%BF%E7%A8%8B/

LinkedList特性

LinkedList继承自Deque,它是一个双端队列,允许在队列的两端插入和删除元素。可以作为栈(LIFO)或队列(FIFO)使用。基于链表(双向链表)实现,可以高效地插入和删除元素。 offer:给链表尾部插入元素,返回值表示是否插入成功 peek:取出头部节点,如果没有则返回null poll:取出头部节点,如果没有则返回null,取完后并把头部节点从队列中移除 remove:移除头部节点,如果没有头部节点则抛异常,有的话,则返回 push:给链表头部插入元素,没有返回值 pop:和remove一样的,都是移除头部节点,如果没有头部节点则抛异常,有的话,则返回

如果想实现队列的话,则使用offer和poll这一对方法;如果想实现栈的话,可以通过offerLast和pollLast来实现,或者通过offerFirst和pollFirst来实现。

ArrayDeque特性

它也是继承自Deque,和LinkedList的特性一样的,只不过ArrayDeque是通过数组实现的双端队列,内部用一个数组来放所有的节点,并且有两个int值用来存放头结点和尾结点的索引。并且ArrayDeque内部的默认节点容量是16个,也可以初始化容量大小。

区别:如果频繁要插入和删除操作,那么使用LinkedList,如果是查询情况比较多,可以优先使用ArrayDeque。

Pools.Pool

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
class Pools private constructor() {
    /**
     * Interface for managing a pool of objects.
     *
     * @param T The pooled type.
     */
    interface Pool<T : Any> {
        /**
         * @return An instance from the pool if such, null otherwise.
         */
        fun acquire(): T?

        /**
         * Release an instance to the pool.
         *
         * @param instance The instance to release.
         * @return Whether the instance was put in the pool.
         *
         * @throws IllegalStateException If the instance is already in the pool.
         */
        fun release(instance: T): Boolean
    }

    /**
     * Simple (non-synchronized) pool of objects.
     *
     * @param maxPoolSize The maximum pool size
     * @param T The pooled type.
     */
    open class SimplePool<T : Any>(
        /**
         * The max pool size
         */
        @IntRange(from = 1) maxPoolSize: Int
    ) : Pool<T> {
        private val pool: Array<Any?>
        private var poolSize = 0

        init {
            require(maxPoolSize > 0) { "The max pool size must be > 0" }
            pool = arrayOfNulls(maxPoolSize)
        }

        override fun acquire(): T? {
            if (poolSize > 0) {
                val lastPooledIndex = poolSize - 1
                @Suppress("UNCHECKED_CAST")
                val instance = pool[lastPooledIndex] as T
                pool[lastPooledIndex] = null
                poolSize--
                return instance
            }
            return null
        }

        override fun release(instance: T): Boolean {
            check(!isInPool(instance)) { "Already in the pool!" }
            if (poolSize < pool.size) {
                pool[poolSize] = instance
                poolSize++
                return true
            }
            return false
        }

        private fun isInPool(instance: T): Boolean {
            for (i in 0 until poolSize) {
                if (pool[i] === instance) {
                    return true
                }
            }
            return false
        }
    }

    /**
     * Synchronized pool of objects.
     *
     * @param maxPoolSize The maximum pool size
     * @param T The pooled type.
     */
    open class SynchronizedPool<T : Any>(maxPoolSize: Int) : SimplePool<T>(maxPoolSize) {
        private val lock = Any()
        override fun acquire(): T? {
            synchronized(lock) { return super.acquire() }
        }

        override fun release(instance: T): Boolean {
            synchronized(lock) { return super.release(instance) }
        }
    }
}

很明显这是一个对象池,SimplePool继承自Pool,并且可以指定对象池的大小。每次要回收的时候调用release,只有当前size小于对象池最大容量的时候才能回收,每次通过acquire来进行获取对象池中的元素。
其中在recyclerview动画篇章中,分析到InfoRecord对象中会使用Pools.SimplePool,InfoRecord存储的是ViewHolder在pre-layout阶段的坐标信息和post-layout阶段的坐标信息,以及ViewHolder的flag信息。因为ViewHolder的这些信息在动画处理过程中会频繁使用,所以此处使用了对象池来管理。

Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy