问题描述
是否可以使用Java的Kotlin反射?
我想从Java中的Kotlin函数获得KCallable
,并使用其方法callBy
来调用带有默认参数的方法。
科特林的例子:
fun test(a: String = "default",b: String): String {
return "A: $a - B: $b";
}
fun main() {
val callable: KCallable<*> = ::test
val parameterB = callable.parameters[1]
val result = callable.callBy(mapOf(
parameterB to "test"
))
println(result)
}
有可能吗?如果是这样,如何从Java代码获取KCallable
的实例?
编辑:
我不能按照建议使用@JvmOverloads
,因为参数,默认参数及其位置可以是任意的。
已知的呼叫信息是:
- 参数名称
- 他们的类型
- 他们的价值
编辑2:
@JvmOverloads
在此处无效的示例:
fun test(a: String = "default",b: String = "default"): String {
return "A: $a - B: $b";
}
解决方法
如果声明了test
函数的文件为Utils.kt
,则它将被编译为UtilsKt
类。
作为文档states:
通常,如果您使用默认参数值编写Kotlin函数,则该函数在Java中仅作为具有所有参数存在的完整签名可见。如果希望向Java调用者公开多个重载,可以使用@JvmOverloads批注。
因此,添加此注释后:
@JvmOverloads
fun test(a: String = "default",b: String): String {
return "A: $a - B: $b";
}
可以使用单个参数从Java调用 test
方法:
public class ReflectionInterop {
public static void main(String[] args) throws NoSuchMethodException,InvocationTargetException,IllegalAccessException {
Method test = UtilsKt.class.getDeclaredMethod("test",String.class);
String result = (String) test.invoke(null,"test"); //null used because method is compiled as static,so no instance needed to call it
System.out.println(result); //Will print "A: default - B: test"
}
}
编辑
如果您正在寻找一种方法来克服方便的Java互操作的局限性,那么您确实需要在Java代码中获得KCallable
的实例。
我相信没有辅助Kotlin功能是不可能的:
fun testReflection(): KCallable<*> = ::test
它在Java中的用法非常简单:
public class ReflectionInterop {
public static void main(String[] args) {
KCallable<?> test = UtilsKt.testReflection(); //Assuming it is located in the same `Utils.kt` file
KParameter parameterB = test.getParameters().get(1);
String result = (String) test.callBy(new HashMap<>() {{
put(parameterB,"test");
}});
System.out.println(result); //Will print "A: default - B: test"
}
}