Kotlin 扩展函数访问 Java 私有字段
Kotlin extension function access Java private field
我想在使用 Kotlin 扩展函数 时访问 Java 的 私有字段 。
假设我有一个JavaclassABC
。 ABC
只有一个私有字段 mPrivateField
。我想在 Kotlin 中编写一个扩展函数,无论出于何种原因使用该字段。
public class ABC {
private int mPrivateField;
}
Kotlin 函数将是:
private fun ABC.testExtFunc() {
val canIAccess = this.mPrivateField;
}
我得到的错误是:
Cannot access 'mPrivateField': It is private in 'ABC'
有什么方法可以绕过这个限制吗?
这在设计上是不可能的。扩展函数本质上解析为以接收者为第一个参数的静态函数。因此,扩展函数
fun String.foo() {
println(this)
}
编译成类似的东西:
public static void foo(String $receiver) {
System.out.println($receiver);
}
现在可以清楚地看到您无法访问 $receiver
的私有成员,因为它们是私有成员。
如果您真的想要访问该成员,您可以使用反射来实现,但您将失去所有保证。
正如 nhaarman 建议的那样,我使用 reflection 来访问相关字段。具体来说,我创建了一个 getter,它在提到的 class 内部使用了反射(即 ABC
)
遗憾的是,截至 2017 年 7 月
,无法访问 Kotlin 扩展函数中的私有字段
fun ABC.testExtFunc() {
val canIAccess = this.getmPrivateField()
}
fun ABC.getmPrivateField() : Int {
val field = this.javaClass.declaredFields
.toList().filter { it.name == "mPrivateField" }.first()
field.isAccessible = true
val value = field.get(this)
return value as Int
}
首先你需要获取一个Field并启用它在Kotlin中可以访问,例如:
val field = ABC::class.java.getDeclaredField("mPrivateField")
field.isAccessible = true
然后,您可以通过Field#getInt从声明class的实例中读取字段值为Int
,例如:
val it: ABC = TODO()
val value = field.getInt(it)
最后,您的扩展方法如下所示:
private inline fun ABC.testExtFunc():Int {
return javaClass.getDeclaredField("mPrivateField").let {
it.isAccessible = true
val value = it.getInt(this)
//todo
return@let value;
}
}
用通用类型扩展holi-java的答案:
- 创建扩展
fun<T: Any> T.accessField(fieldName: String): Any? {
return javaClass.getDeclaredField(fieldName).let { field ->
field.isAccessible = true
return@let field.get(this)
}
}
- 访问私有字段
val field = <your_object_instance_with_private_field>
.accessField("<field_name>")
as <object_type_of_field_name>
示例:
class MyClass {
private lateinit var mObject: MyObject
}
val privateField = MyClass()
.accessField("mObject")
as MyObject
使用以下扩展函数获取私有变量
fun <T : Any> T.getPrivateProperty(variableName: String): Any? {
return javaClass.getDeclaredField(variableName).let { field ->
field.isAccessible = true
return@let field.get(this)
}
}
设置私有变量值获取变量
fun <T : Any> T.setAndReturnPrivateProperty(variableName: String, data: Any): Any? {
return javaClass.getDeclaredField(variableName).let { field ->
field.isAccessible = true
field.set(this, data)
return@let field.get(this)
}
}
获取变量使用:
val bool = <your_class_object>.getPrivateProperty("your_variable") as String
设置和获取变量使用:
val bool = <your_class_object>.setAndReturnPrivateProperty("your_variable", true) as Boolean
val str = <your_class_object>.setAndReturnPrivateProperty("your_variable", "Hello") as String
我想在使用 Kotlin 扩展函数 时访问 Java 的 私有字段 。
假设我有一个JavaclassABC
。 ABC
只有一个私有字段 mPrivateField
。我想在 Kotlin 中编写一个扩展函数,无论出于何种原因使用该字段。
public class ABC {
private int mPrivateField;
}
Kotlin 函数将是:
private fun ABC.testExtFunc() {
val canIAccess = this.mPrivateField;
}
我得到的错误是:
Cannot access 'mPrivateField': It is private in 'ABC'
有什么方法可以绕过这个限制吗?
这在设计上是不可能的。扩展函数本质上解析为以接收者为第一个参数的静态函数。因此,扩展函数
fun String.foo() {
println(this)
}
编译成类似的东西:
public static void foo(String $receiver) {
System.out.println($receiver);
}
现在可以清楚地看到您无法访问 $receiver
的私有成员,因为它们是私有成员。
如果您真的想要访问该成员,您可以使用反射来实现,但您将失去所有保证。
正如 nhaarman 建议的那样,我使用 reflection 来访问相关字段。具体来说,我创建了一个 getter,它在提到的 class 内部使用了反射(即 ABC
)
遗憾的是,截至 2017 年 7 月
,无法访问 Kotlin 扩展函数中的私有字段fun ABC.testExtFunc() {
val canIAccess = this.getmPrivateField()
}
fun ABC.getmPrivateField() : Int {
val field = this.javaClass.declaredFields
.toList().filter { it.name == "mPrivateField" }.first()
field.isAccessible = true
val value = field.get(this)
return value as Int
}
首先你需要获取一个Field并启用它在Kotlin中可以访问,例如:
val field = ABC::class.java.getDeclaredField("mPrivateField")
field.isAccessible = true
然后,您可以通过Field#getInt从声明class的实例中读取字段值为Int
,例如:
val it: ABC = TODO()
val value = field.getInt(it)
最后,您的扩展方法如下所示:
private inline fun ABC.testExtFunc():Int {
return javaClass.getDeclaredField("mPrivateField").let {
it.isAccessible = true
val value = it.getInt(this)
//todo
return@let value;
}
}
用通用类型扩展holi-java的答案:
- 创建扩展
fun<T: Any> T.accessField(fieldName: String): Any? {
return javaClass.getDeclaredField(fieldName).let { field ->
field.isAccessible = true
return@let field.get(this)
}
}
- 访问私有字段
val field = <your_object_instance_with_private_field>
.accessField("<field_name>")
as <object_type_of_field_name>
示例:
class MyClass {
private lateinit var mObject: MyObject
}
val privateField = MyClass()
.accessField("mObject")
as MyObject
使用以下扩展函数获取私有变量
fun <T : Any> T.getPrivateProperty(variableName: String): Any? {
return javaClass.getDeclaredField(variableName).let { field ->
field.isAccessible = true
return@let field.get(this)
}
}
设置私有变量值获取变量
fun <T : Any> T.setAndReturnPrivateProperty(variableName: String, data: Any): Any? {
return javaClass.getDeclaredField(variableName).let { field ->
field.isAccessible = true
field.set(this, data)
return@let field.get(this)
}
}
获取变量使用:
val bool = <your_class_object>.getPrivateProperty("your_variable") as String
设置和获取变量使用:
val bool = <your_class_object>.setAndReturnPrivateProperty("your_variable", true) as Boolean
val str = <your_class_object>.setAndReturnPrivateProperty("your_variable", "Hello") as String