Kotlin中如何通过反射获取私有方法并传入高阶函数
报错核心原因
- 你通过反射拿到的
KFunction<*>是Kotlin反射体系的成员函数类型,本身不属于Kotlin高阶函数要求的() -> Unit普通函数类型,强制转型会触发运行时异常 - 类的成员方法本身隐含持有当前实例的this引用,直接调用的话必须绑定实例对象,不能直接当作无参函数使用
方案1:直接包装lambda(最小改动,无需修改原有工具函数)
你不需要对getPrivateFunc做任何修改,只需要在传参的时候用lambda把反射调用逻辑包起来即可,lambda本身符合() -> Unit的类型要求:
val service = MyService() val sut = SystemUnderTest() val privateMethod = sut.getPrivateFunc("privateFunc") // 直接用lambda包装调用逻辑 service.myHigherOrderFunction { privateMethod.call(sut) }
如果私有方法带参数,只需要在call方法里按顺序传入参数即可,比如方法定义为private fun privateFunc(count: Int, name: String),调用的时候写privateMethod.call(sut, 10, "test")即可。
方案2:优化扩展函数,直接返回绑定实例的函数类型
如果需要频繁调用这类反射方法,可以优化扩展函数,提前把实例绑定到返回的函数中,用的时候直接传即可:
无参私有方法版本
inline fun <reified T> T.getBoundPrivateNoArgFunc(name: String): () -> Unit { val kFunction = T::class.declaredMemberFunctions.first { it.name == name }.apply { isAccessible = true } // 提前绑定当前实例,返回符合要求的函数类型 return { kFunction.call(this@getBoundPrivateNoArgFunc) } }
调用示例
val privateFunc = sut.getBoundPrivateNoArgFunc("privateFunc") // 直接传入即可,无需额外包装 service.myHigherOrderFunction(privateFunc)
通用多参数版本
如果需要支持不同参数数量的私有方法,可以按参数数量重载扩展函数,比如支持1个参数的版本:
inline fun <reified T, P, R> T.getBoundPrivateFunc(name: String): (P) -> R { val kFunction = T::class.declaredMemberFunctions.first { it.name == name }.apply { isAccessible = true } return { p -> kFunction.call(this@getBoundPrivateFunc, p) as R } }
注意事项
- 调用
call方法的返回值默认是Any?类型,如果需要拿到返回值可以手动做类型转换,不会有类型转换异常 - 私有方法的名称如果拼写错误会抛出
NoSuchElementException,可以根据需要在扩展函数里加空安全处理或者自定义异常
内容的提问来源于stack exchange,提问作者Alejandro Casanova
相关产品推荐
相关产品推荐

