如何在Kotlin中通过反射获取运行时才知晓名称的类成员函数引用
在Kotlin中通过运行时方法名反射获取并存储方法引用
嗨,刚好碰到过类似的场景,我来帮你搞定这个问题~
你想要的是在运行时动态拿到方法的引用,存到变量里随时调用,而不是每次调用都要折腾实例对吧?之前你尝试的方式其实没走错方向,只是差了一步「绑定实例」的操作,或者可以直接用Kotlin原生的反射API更顺手。
先看你的示例类:
class X { fun Y() { println("Method Y executed!") } }
方法一:用Kotlin反射API获取未绑定的函数引用
如果你只是想先拿到方法的引用,之后再传入不同实例调用,可以这么做:
// 假设运行时拿到的方法名 val targetMethodName = "Y" // 从X的KClass中找到对应名称的方法 val kFunction = X::class.members .find { it.name == targetMethodName && it is KFunction<*> } ?.let { it as KFunction<Unit> } // 调用时需要传入实例 val x1 = X() kFunction?.call(x1) // 输出 Method Y executed! val x2 = X() kFunction?.call(x2) // 可以用同一个函数引用调用不同实例
这里X::class.members会列出类的所有成员(方法、属性等),我们通过名称和类型筛选出目标方法,强转成KFunction<Unit>是因为你的Y()方法无参且返回Unit。
方法二:绑定实例,得到可直接调用的函数变量
如果已经确定了要使用的实例,想把「实例+方法」绑定成一个可以直接调用的变量(比如() -> Unit类型),那就用bind()方法:
val xInstance = X() // 绑定实例到函数引用上,得到一个无参函数 val boundMethod: (() -> Unit)? = kFunction?.bind(xInstance) as? () -> Unit // 现在直接调用变量就行,不用再传实例了 boundMethod?.invoke() // 或者更简洁的写法:boundMethod?.()
这样你就可以把boundMethod存在变量里,需要的时候直接调用,完全符合你的需求~
关于你之前的尝试
你之前用X::class.java.getMethod("Y").kotlinFunction其实也能拿到KFunction<*>,本质和上面的kFunction是一样的,只是走了Java反射再转Kotlin的路子。之所以你觉得「需要实例才能调用毫无意义」,是因为成员方法本身就依赖实例(毕竟每个实例的状态可能不同),而绑定实例之后就解决了这个问题,把它变成了一个不需要额外参数的函数。
如果你的方法有参数,只需要调整泛型类型就行,比如Y(a: Int)的话,绑定后就是((Int) -> Unit)?,调用的时候传入参数即可。
内容的提问来源于stack exchange,提问作者Tito Tigi




