Kotlin中reified理解和实战应用
文章目录
Kotlin提供了一个reified
关键字,这个关键字在实际项目中有很大的用处,比如泛型相关的封装,SDK封装等。今天我们就来学习下这块的知识。首先需要先了解下内联函数,也就是inline
关键字
内联函数(inline)
在Kotlin中内联函数就是用关键字inline
修饰的函数,它有什么作用呢?我看下面一段代码
|
|
很简单的一段代码,编译成apk后,我们可以看下它对应Class文件,代码如下:
|
|
从上面的反编译的代码可以看到:
- 在调用内联函数的地方,不再是一个函数,而是函数内的代码块
- 而原来单独的getUserInfo
函数还是存在,且函数参数编译成了对应的FunctionN
对象
上从面可以知道,内联函数在被调用时,并不是分配栈调用函数,而是在编译时,把内联函数中的代码块替换到调用处。
优点
为什么会引入inline的概念呢?主要的原因我个人认为有两个:
- 使用inline
特性,性能上会有所提升,因为减少了调用函数时的内存,函数参数对象的创建等
- 因为Kotlin支持高阶函数,存在大量的匿名函数,lambda
,使用inline
可以减少中间类的创建
注意:如果内联函数的代码块很多,那么有可能导致调用处的函数代码量很大。
reified
说这个之前,我先看下在Java中,如何实例化一个泛型对象?我们唯一的办法是像下面这样:
|
|
只能通过传递Class
的方式来创建,是因为存在泛型擦除的机制,无法知道T
到底是什么类型,无法获取泛型T
的Class
,所以只能在调用处,通过参数传递进来。
在Kotin中,同样也存在泛型擦除,但是他为了解决这个问题,新增了一个 reified
关键字,这个关键字的主要作用就是可以具体化泛型T
的类型。
我们现在用reified
关键字实现一个实例化泛型对象的工具方法,如下:
|
|
可以看到,我们不用像Java一样传递泛型的具体Class
,直接可以通过泛型拿到Class。在之前的Kotlin属性委托的巧妙使用-埋点上报封装中,我们就是利用到了这个原理实现了埋点的封装上报,非常的方便有效,是封装库的利器。
因为类型已知,所以正常的操作符如!is
和as
现在都能正常使用。那之前的我们封装SharedPreferences
保存key-value的那种方式都可以重新利用这个特性进行封装。
注意:
reified
参数只能用在内联函数中
原理
那为什么会有这个效果呢?我们先看一个例子:
|
|
上面是是一段很简单的代码,就是打印泛型t的值。我们反编译最后生成的class类,结果如下:
|
|
从反编译的结果可以看出,调用的方法没有了,反而只有getUserInfo
方法内的代码块,而日志中的T
,直接替换成了调用方法传递进去的值hello refied
。
从这可以明白为什么reified要和内联函数一期使用,主要原因就是编译器在编译的时候,会把内联函数的代码替换到调用处。而reified
关键字修饰的泛型T
,会泛型T直接替换为调用处实际的数据类型。
文章作者 卒子行
上次更新 2023-09-21