有什么方法可以将函数传递给带有参数 KFunction 的方法吗? 我在 kotlin 中有一个库,我想在 java 中使用它,但我无法将 Function 转换为 KFunction (?)。 我想传递java函数的函数
// For example it will be in Event class
fun register(value: KFunction1<Value,Unit>) {
...
}
My 尝试将函数传递给 kfunction
public class Test {
public void launch() {
Event.register(Test::test); // Error
}
@Subscriber
public static Unit test(Value data) {
System.out.println("Hello world!");
return Unit.INSTANCE;
}
}
附言。由于注释的使用,我需要它是 KFunction
您可以制作一个
KFunction
接受函数的 Kotlin 包装器,它采用函数类型:
fun registerHelper(value: (Value) -> Unit) {
register(value::invoke)
}
然后可以从 Java 代码中调用:
public class Test {
public void launch() {
registerHelper(Test::test);
}
@Subscriber
public static Unit test(Value data) {
System.out.println("Hello world!");
return Unit.INSTANCE;
}
}
但是,如果
registerHelper
需要访问test
的名字,或者上面的注解,而不是仅仅调用它,那就难多了。
我能想到的一种方法是您在 kotlin 中执行的操作,当您想要将
java.lang.reflect.Method
转换为 KFunction
时。你会用kotlinFunction
,对吧?
kotlinFunction
属性对应Java中称为ReflectJvmMapping.getKotlinFunction
的静态方法。
您可以将
test
方法作为java.lang.reflect.Method
,然后使用它来转换为KFunction
:
var testClass = Test.class;
var method = testClass.getMethod("test", Value.class);
// note the unchecked cast here, which is safe as long as you got the correct method
Event.register((KFunction<Unit>) ReflectJvmMapping.getKotlinFunction(method));
由于
getKotlinFunction
的实现再次使用了Kotlin反射来查找函数,所以如果您先将Test.class
转换为Kotlin类,然后直接使用Kotlin反射可能会更好
var testClassKotlin = JvmClassMappingKt.getKotlinClass(Test.class);
var kfunction = KClasses.getFunctions(testClassKotlin).stream()
// use whatever criteria to find the method you want
.filter(x -> x.getName().equals("test"))
.findFirst().get();
也就是说,当您编写函数引用时,这不是 Kotlin 编译器在内部生成
KFunction
的方式。 kotlin 编译器实际上创建了kotlin.jvm.internal.FunctionReferenceImpl
的子类。如果你想做编译器做的事情,我真的不推荐:
// yes, implementing the raw type of Function1 is necessary.
class SomeInnerClass extends FunctionReferenceImpl implements kotlin.jvm.functions.Function1{
public SomeInnerClass() {
// here you need to pass in the arty, declared class, name,
// JVM signature, and some flags too
super(1, Test.class, "test", "test(Lyourpackage/Value;)Lkotlin/Unit;", 0);
// For what the flags mean, see
// https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/FunctionReference.java#L16
}
@Override
public Unit invoke(Object value) {
return Test.test((Value)value);
}
}
然后将此实例传递给
register
.