Kotlin 中的 inline 和 reified 关键字

在 Kotlin 里,inline 和 reified 经常成对出现,但它们各自解决的问题并不一样。下面把两个关键字拆开讲,再给出它们"合体"时的典型用法。


  1. inline ------ 消除"函数对象"的开销

背景

Kotlin 的高阶函数(参数里带 lambda)会被编译成对象。每次调用都生成一个匿名类/对象,带来:

  • 内存分配
  • 虚方法调用
  • 运行时实例化

inline 做了什么

函数体 以及传给它的 lambda 字节码原地展开(copy-paste),彻底消除上述开销。

示例

kotlin 复制代码
// 未 inline
fun measure(block: () -> Unit) {
    val t0 = System.nanoTime()
    block()
    println("cost ${System.nanoTime() - t0} ns")
}

// 调用
measure { println("hello") }

反编译后能看到 measure 里出现了 Function0 实例。

加上 inline:

kotlin 复制代码
inline fun measure(block: () -> Unit) {
    val t0 = System.nanoTime()
    block()
    println("cost ${System.nanoTime() - t0} ns")
}

反编译结果里只剩下一行 println("hello") 和计时代码,没有任何 Function0

额外效果

  • return 可以"非局部"返回(lambda 里直接返回外层函数)。
  • 整个调用栈在调试器里变"平",断点会停在展开后的行号。

  1. reified ------ 把"擦除"的类型"找回来"

背景

JVM 泛型在运行时会被擦除,因此下面代码编译失败:

kotlin 复制代码
fun <T> Bundle.get(): T? = this.getSerializable("key") as? T   // 警告:unchecked cast

问题

运行时无法判断 T 具体是什么,因而无法安全转换。

reified 做了什么

只有 inline 函数才能加 reified;它把类型实参 也写进字节码里,于是运行时就能拿到 Class 对象。

示例

kotlin 复制代码
inline fun <reified T> Bundle.get(): T? =
    if (T::class.java.isPrimitive) null
    else this.getSerializable("key") as? T

调用

kotlin 复制代码
val user: User? = bundle.get<User>()

反编译后能看到:

java 复制代码
User $tmp = (User) bundle.getSerializable("key");

User.class 被直接硬编码在调用处,因此运行期可以安全强转。


  1. 合体:inline + reified 的典型套路

  1. 启动 Activity(Android)
kotlin 复制代码
inline fun <reified T : Activity> Context.startActivity() {
    startActivity(Intent(this, T::class.java))
}

调用:

kotlin 复制代码
startActivity<DetailActivity>()
  1. 获取日志 Tag
kotlin 复制代码
inline fun <reified T> T.logger(): Logger = LoggerFactory.getLogger(T::class.java)
  1. Gson 一行反序列化
kotlin 复制代码
inline fun <reified T> Gson.fromJson(json: String): T = fromJson(json, T::class.java)

  1. 小结一句话

  • inline性能+控制流关键字:消除 lambda 对象、允许非局部返回。
  • reified类型信息关键字:只能配合 inline,让泛型类型在运行期"不擦除"。
相关推荐
一晌小贪欢1 小时前
Python 爬虫进阶:如何利用反射机制破解常见反爬策略
开发语言·爬虫·python·python爬虫·数据爬虫·爬虫python
阿猿收手吧!2 小时前
【C++】异步编程:std::async终极指南
开发语言·c++
我有与与症2 小时前
从页面加载过程看 Kuikly 的多线程架构
kotlin
doupoa2 小时前
内存指针是什么?为什么指针还要有偏移量?
android·c++
小程故事多_802 小时前
Agent Infra核心技术解析:Sandbox sandbox技术原理、选型逻辑与主流方案全景
java·开发语言·人工智能·aigc
沐知全栈开发2 小时前
SQL 日期处理指南
开发语言
黎雁·泠崖2 小时前
【魔法森林冒险】3/14 Allen类(一):主角核心属性与初始化
java·开发语言
黎雁·泠崖2 小时前
【魔法森林冒险】1/14 项目总览:用Java打造你的第一个回合制冒险游戏
java·开发语言
独好紫罗兰2 小时前
对python的再认识-基于数据结构进行-a006-元组-拓展
开发语言·数据结构·python
C++ 老炮儿的技术栈2 小时前
Qt 编写 TcpClient 程序 详细步骤
c语言·开发语言·数据库·c++·qt·算法