Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin扩展函数访问Java专用字段_Kotlin_Kotlin Extension_Kotlin Interop - Fatal编程技术网

Kotlin扩展函数访问Java专用字段

Kotlin扩展函数访问Java专用字段,kotlin,kotlin-extension,kotlin-interop,Kotlin,Kotlin Extension,Kotlin Interop,我想在使用Kotlin扩展功能时访问Java的私有字段 假设我有一个Java类ABCABC只有一个专用字段mPrivateField。我想在Kotlin中编写一个扩展函数,无论出于什么原因使用该字段 public class ABC { private int mPrivateField; } Kotlin功能将是: private fun ABC.testExtFunc() { val canIAccess = this.mPrivateField; } 我得到的错误是:

我想在使用Kotlin扩展功能时访问Java的私有字段

假设我有一个Java
ABC
<代码>ABC只有一个专用字段
mPrivateField
。我想在Kotlin中编写一个扩展函数,无论出于什么原因使用该字段

public class ABC {
    private int mPrivateField;

}
Kotlin功能将是:

private fun ABC.testExtFunc() {
    val canIAccess = this.mPrivateField;
}
我得到的错误是:

无法访问“mPrivateField”:它在“ABC”中是私有的


有没有办法绕过这个限制?

这是设计上不可能的。扩展函数本质上分解为静态函数,并将接收器作为其第一个参数。因此,一个扩展函数

fun String.foo() {
  println(this)
}
编译为如下内容:

public static void foo(String $receiver) {
  System.out.println($receiver);
}
现在可以清楚地看到,您无法访问
$receiver
的私有成员,因为它们是私有的


如果您确实想访问该成员,可以使用反射来访问,但您将失去所有保证。

正如nhaarman所建议的那样,我使用反射来访问相关字段。具体地说,我创建了一个getter,它在所提到的类(即
ABC
)的内部使用反射

遗憾的是,截至2017年7月,无法访问Kotlin扩展功能中的私有字段


首先,您需要获取并启用一个可在Kotlin中访问的,例如:

val field = ABC::class.java.getDeclaredField("mPrivateField")

field.isAccessible = true
val it: ABC = TODO()

val value = field.getInt(it)
然后,您可以从声明类的实例中将字段值读取为
Int
by,例如:

val field = ABC::class.java.getDeclaredField("mPrivateField")

field.isAccessible = true
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.getPrivateProperty(variableName: String): Any? {
        return javaClass.getDeclaredField(variableName).let { field ->
            field.isAccessible = true
            return@let field.get(this)
        }
    }
    
    fun T.getPrivateProperty(variableName:String):有吗?{
    返回javaClass.getDeclaredField(variableName).let{field->
    field.isAccessible=true
    return@let字段。获取(此)
    }
    }
    
    设置私有变量值获取变量

    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)
        }
    }
    
    fun T.setAndReturnPrivateProperty(variableName:String,data:Any):Any?{
    返回javaClass.getDeclaredField(variableName).let{field->
    field.isAccessible=true
    field.set(此字段,数据)
    return@let字段。获取(此)
    }
    }
    
    获取变量使用:

    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
    
    val bool=.getPrivateProperty(“您的变量”)作为字符串
    
    设置并获取变量使用:

    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
    
    val bool=.setAndReturnPrivateProperty(“您的_变量”,true)作为布尔值
    val str=.setAndReturnPrivateProperty(“您的_变量”、“您好”)作为字符串
    
    为什么需要访问java私有字段?它来自一个外部编译库,我想扩展它,而不在我的项目中包含整个源代码。库中有用于Android日历事件的“get”方法,我想将“insert Calendar event”功能添加到类中。修改外部库私有字段是危险的。它可能会毁了你的申请。您可以使用java更改字段值。是的,我同意。但我只想得到那个领域。使用它的方法就像我扩展的类一样。这里没有真正的威胁…我希望kotlin的人能够自动生成反射方法,以简化将来的私有字段获取程序。。。虽然我同意在大多数情况下这并不安全,但那是不可能发生的。任何人都不应该鼓励这样的反思。Android平台上的轶事承诺:。在这种情况下,谷歌不得不回滚一个私人成员的重命名,因为Facebook是通过反射访问它的。你可以直接使用
    Class#getDeclaredField
    &
    Field#getInt
    。因为您确切地知道要获取的字段。这是一个以内联方式解决问题的干净解决方案。无需定义单独的扩展getter。Thanks@kosiara-BartoszKosarzycki当然,你可以,如果你愿意,你可以把函数变成内联函数。然而,当您想要使操作抽象时,扩展是必需的,例如:
    testExtFunc(action:(Int)->R)
    ,将读取逻辑与
    操作
    逻辑分开,并且您可以在任何地方重用读取函数
    testExtFunc
    。然后您可以将其用作,
    testExtFunc(foo)
    testExtFunc(bar)
    它们就像
    /
    在kotlin中运行
    /
    应用
    和.etc。如何获取具有侦听器类型的字段,如
    复合按钮中的
    mOnCheckedChangeListener
    ?超级!对我有用。谢谢