2024年Kotlin 浅谈 reified 与泛型 那些事_kotlin reified 原理(1),大厂面试经验分享稿

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

Class c1=new ArrayList<Integer>().getClass();
Class c2=new ArrayList<String>().getClass();
// 输出为true
System.out.println(c1==c2);

上述输出结果为什么会true呢?

因为泛型从底层上说是一种语法糖,它只存在于 编译期 。在代码运行期间,jvm会将泛型的相关信息擦除,成功编译后的 class文件 不会包含任何泛型信息。所以在运行时,c1与c2存储的类型都为Object,而 Integer 与 String 已经被擦除。

正是由于类型被擦除,所以就导致一些相关问题,比如不安全的类型转换,模版方法的增多等。

reified

为了解决上述类型擦除问题,以及更好的使用体验。Kotlin 中存在名为 reified 的关键字,它可以被作用于函数上, 以此做到类型擦除后的再生,便于开发者优雅的使用泛型以及获取方法的泛型类型。

Java 中,如果我们要获取函数的泛型类型,一般会通过给函数中传递类型参数的方式,如下所示:

public <T extends Activity> void startActivity(Context context, Class<T> c) {
     context.startActivity(new Intent(context, c));
 }

如果上述代码使用 kotlin 来写呢?如下所示:

inline fun <reified C : Activity> Context.startActivityKtx() {
    startActivity(Intent(this, C::class.java))
}

我们利用 扩展函数 + reified 关键字的方式,减少了模版代码,增强了使用体验。

从而让本该在编译阶段被擦除的Activity类型,能够在运行时获取到。

但需要注意的是,reified 关键字必须和 inline 关键字一起使用(下面会提到为什么)。

inline 关键字是什么呢?

简单理解为:当一个函数被标记为 inline 时,kotlin编译器 会在所有调用这个函数的位置,将方法函数替换为具体的函数体。

解析

通过查看 kotlin 字节码,我们可以得知 reified 的底层实现。

例如下面示例与其对应的字节码:

inline fun <reified C : Activity> Context.toAct() {
    startActivity(Intent(this, C::class.java))
}

fun test(context: Context) {
    context.toAct<MainActivity>()
}

// $FF: synthetic method
public static final void toAct(Context $this$toAct) {
   int $i$f$toAct = 0;
   Intrinsics.checkNotNullParameter($this$toAct, "$this$toAct");
   Intrinsics.reifiedOperationMarker(4, "C");
   $this$toAct.startActivity(new Intent($this$toAct, Activity.class));
}

public static final void test(@NotNull Context context) {
   Intrinsics.checkNotNullParameter(context, "context");
   int $i$f$toAct = false;
   context.startActivity(new Intent(context, MainActivity.class));
}

我们在 test() 方法中调用toAct(),不难发现,toAct()的逻辑已经被移动到了 test() 中,而我们的泛型类型也被替换为实际使用的类型,从而我们可以在方法函数中直接获取相应的泛型类型。

这也就是为什么 reified 必须要增加 inline ,因为其必须内联才能知道具体类型,从而将我们的实际泛型类型更新到具体的调用代码中,从而完成泛型类型 再生

小提示

Java中无法调用

需要注意的是,reified 无法在java中进行调用,为什么呢?

因为 Java 并没有内联的特性,我们使用的 inline 方法在 Java 中会被当做普通方法,而 reified 正是需要内联才可以保证泛型再生,所以自然无法调用。

从源码上来说,对于reified 关键字的方法,相应的字节码生成时会增加 // $FF: synthetic method 的标记。

如下示例所示:

inline fun <reified C : Activity> Context.toAct() {


**深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

![](https://img-blog.csdnimg.cn/direct/743b668910224b259a5ffe804fa6d0db.png)
![img](https://img-blog.csdnimg.cn/img_convert/03a98bfdc1d583f3af411f56b3b0ee8f.png)
![img](https://img-blog.csdnimg.cn/img_convert/39dccab2828706e2167f44cfbef8f686.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618636735)**

%以上鸿蒙开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618636735)**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值