如何在 Kotlin 中从类外调用类的私有函数

7

我想要从类 SomeClass 外部调用该类的私有函数:

class SomeClass {
    private fun somePrivateFunction() {
        //...
    }

    private fun somePrivateFunctionWithParams(text: String) {
        //...
    }
}

在代码的某个地方,我引用了一个SomeClass对象:

val someClass = SomeClass()
// how can I call the private function `somePrivateFunction()` from here?
// how can I call the private function `somePrivateFunctionWithParams("some text")` from? here

如何在 Kotlin 中从类外部调用带参数和不带参数的私有函数?
3个回答

7

我发现了两个使用反射的有用扩展函数:

inline fun <reified T> T.callPrivateFunc(name: String, vararg args: Any?): Any? =
    T::class
        .declaredMemberFunctions
        .firstOrNull { it.name == name }
        ?.apply { isAccessible = true }
        ?.call(this, *args)

inline fun <reified T : Any, R> T.getPrivateProperty(name: String): R? =
    T::class
        .memberProperties
        .firstOrNull { it.name == name }
        ?.apply { isAccessible = true }
        ?.get(this) as? R

为在Kotlin中使用反射,请添加依赖项:
``` implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" ```
以下函数可按如下方式使用:
class SomeClass {

    private val world: World = World()

    private fun somePrivateFunction() {
        println("somePrivateFunction")
    }

    private fun somePrivateFunctionWithParams(text: String) {
        println("somePrivateFunctionWithParams()  text=$text")
    }
}

class World {
    fun foo(): String = "Test func"
}

// calling private functions:

val someClass = SomeClass()
someClass.callPrivateFunc("somePrivateFunction")
someClass.callPrivateFunc("somePrivateFunctionWithParams", "test arg")

// getting private member and calling public function on it:

val world = someClass.getPrivateProperty<SomeClass, World>("world")
println(world?.foo())

当使用参数版本时,我遇到了以下错误:"IllegalArgumentException: Callable expects 4 arguments, but 2 were provided." 这很奇怪,因为实际上该函数需要3个参数。您能否更详细地解释一下如何使用参数版本? - SMBiggs
你调用哪个带有参数 version 的函数? - Sergio
我想通了。每个参数都需要在函数名称后作为自己独立的参数。我原以为这些参数都是字符串(也就是第二个参数)的一部分。 - SMBiggs
我想补充一下,设置变量应该是这样的:inline fun <reified T : Any, R> T.setPrivateProperty(name: String, value: R) = T::class .memberProperties .firstOrNull { it.name == name } ?.apply { isAccessible = true } ?.let { (it as? KMutableProperty1<T, R>)?.setter?.call(this, value) } - undefined

5
"private" 的概念是只有在该类内部才能被调用。如果你想要 "闯入" 这个类,你需要利用反射: https://dev59.com/zVYM5IYBdhLWcg3w-Dpf#48159066 根据文档的描述:
"private" 表示只有在该类内部(包括所有成员)才可见。
以下是一个例子:
class WithPrivate {
    private fun privFun() = "you got me"
}

fun main() {
    WithPrivate::class.declaredMemberFunctions.find { it.name == "privFun" }?.let {
        it.isAccessible = true
        println(it.call(WithPrivate()))
    }

}

我认为 OP 想知道如何使用反射来做这件事,但问题中唯一与之相关的提示是反射标签。 - deHaar
2
通过您提供的链接,我了解到如何访问对象的私有字段,但没有关于如何调用对象的私有函数的信息。 - Sergio
添加了一个函数示例,尽管它非常相似。 - s1m0nw1

0
val managerClass = Class.forName("com.api.Manager").kotlin
val managerInstance = managerClass.createInstance()
val startMethod = managerClass
    .declaredMemberFunctions
    .first { it.name == "start" }
    .also { it.isAccessible = true }
val param = 1234
startMethod.call(managerInstance, param)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接