将 Java 函数传递给 KFunction

问题描述 投票:0回答:1

有什么方法可以将函数传递给带有参数 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

java kotlin reflection type-conversion jvm
1个回答
1
投票

您可以制作一个

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
.

© www.soinside.com 2019 - 2024. All rights reserved.