如何从Java使用Kotlin反射

问题描述

是否可以使用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";
}

此处使用一个String值进行调用是不明确的。

解决方法

如果声明了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"
    }
}