英文:
How to use Kotlin reflection from Java
问题
在Java中是否可以使用Kotlin反射?
我想从Kotlin函数中在Java中获取KCallable
,并使用其方法callBy
调用带有默认参数的方法。
Kotlin示例:
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
值进行调用是有歧义的。
英文:
Is it possible to use Kotlin reflection from Java?
I want to get KCallable
from Kotlin function in Java and use its method callBy
to call method with default arguments.
Example in Kotlin:
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)
}
Is it even possible? If so, how to get instance of KCallable
from Java code?
EDIT:
I cannot use @JvmOverloads
as suggested, because the number of arguments, default arguments and their positions can be arbitrary.
The known information for calling is:
- names of arguments
- their type
- their value
EDIT 2:
Example of not working @JvmOverloads
here:
fun test(a: String = "default", b: String = "default"): String {
return "A: $a - B: $b";
}
Here calling with one String
value is ambiguous.
答案1
得分: 1
如果声明了 test
函数的文件是 Utils.kt
,那么它将被编译为 UtilsKt
类。
根据文档的说明:
>通常情况下,如果您编写了一个带有默认参数值的 Kotlin 函数,它在 Java 中只会以完整签名的形式可见,其中包含所有参数。如果您希望向 Java 调用者公开多个重载版本,可以使用 @JvmOverloads
注解。
因此,在添加了此注解之后:
@JvmOverloads
fun test(a: String = "default", b: String): String {
return "A: $a - B: $b";
}
test
方法可以在 Java 中以单个参数调用:
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 用于调用静态方法,因此不需要实例
System.out.println(result); //将打印 "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(); //假设它位于同一个 `Utils.kt` 文件中
KParameter parameterB = test.getParameters().get(1);
String result = (String) test.callBy(new HashMap<>(){{
put(parameterB, "test");
}});
System.out.println(result); //将打印 "A: default - B: test";
}
}
英文:
If file, where test
function was declared, is Utils.kt
, then it will be compiled into UtilsKt
class.
As documentation states:
>Normally, if you write a Kotlin function with default parameter values, it will be visible in Java only as a full signature, with all parameters present. If you wish to expose multiple overloads to Java callers, you can use the @JvmOverloads annotation.
So, after adding this annotation:
@JvmOverloads
fun test(a: String = "default", b: String): String {
return "A: $a - B: $b";
}
test
method may be called from java with a single parameter:
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"
}
}
EDIT
If you are looking for a way to overcome limitations of convenient java interop, then you indeed need to get an instance of KCallable
in your Java code.
I believe it is impossible without auxilary Kotlin function:
fun testReflection(): KCallable<*> = ::test
Its usage in Java is pretty simple:
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"
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论