【问题标题】:kotlin function default arguments from java来自java的kotlin函数默认参数
【发布时间】:2022-03-12 13:08:30
【问题描述】:

鉴于以下 Kotlin 类:

class Foo {
   public fun bar(i: Int = 0): Int = 2 * i
}

我应该如何从 java/groovy 代码中调用没有任何参数的“bar”函数?

def f = new Foo()
f.bar() //throws:  java.lang.IllegalArgumentException: Parameter specified as non-null contains null

【问题讨论】:

标签: kotlin


【解决方案1】:

您现在可以在 Kotlin 中执行此操作。对于您的类方法,请使用@JvmOverloads annotation

class Foo {
    @JvmOverloads public fun bar(name: String = "World"): String = "Hello $name!"
}

现在只需从 Java 中调用它:

Foo foo = new Foo();
System.out.println(foo.bar());
System.out.println(foo.bar("Frank"));

输出以下内容:

世界你好!

你好弗兰克!

【讨论】:

  • 在使用@JvmOverloads 时,请记住以下几点: 1. 在父类/接口上使用默认参数也会影响子实现。无需使重写方法中的参数接受默认参数。默认情况下,它们对所有 Kotlin 使用都这样做。 2.接口方法上不能使用JvmOverloads。导致编译错误。 3. 如果你重写了一个接受默认参数的方法并将参数设置为默认值——会导致编译错误。他们已经接受 Kotlin 使用的默认参数。 4.不能在被覆盖的方法上使用JvmOverloads——签名冲突。
  • 非常感谢@JvmOverloads@mdsayubi 的注意事项
  • @MMK 是的,确实如此。您可以在同一个项目中使用 Kotlin 类和 Java 类轻松地对此进行测试,并查看您的 IDE(假设为 IntelliJ IDEA)向您展示了什么。
【解决方案2】:

我很快就会发布真正的答案,但如果有人想通过反射来做到这一点,代码的外观如下。更复杂,但关于如何将 Kotlin 反射用于 KCallable 的教育。

这是要调用的类:

 class Foo {
    public fun bar(name: String = "World"): String = "Hello $name!"
}

然后我们需要 Kotin 中的实用程序类,它可以接收类的实例、来自 java 反射的方法以及名称参数。这仅适用于非基元:

class KReflectHelper {
    companion object {
        @Suppress("UNCHECKED_CAST")
        @JvmStatic fun <T> callKotlinMethodWithNamedParms(instance: Any, method: Method, parmMap: Map<String, Any>): T {
            val callable: KFunction<T> = method.kotlinFunction as? KFunction<T> ?: throw IllegalStateException("Method is not a Kotlin method")
            val unusedParms = HashSet(parmMap.keys)
            val callableParms = hashMapOf<KParameter, Any?>()
            callable.parameters.map { parm ->
                if (parm.kind == KParameter.Kind.INSTANCE) {
                    callableParms.put(parm, instance)
                } else if (parm.kind == KParameter.Kind.VALUE && parmMap.contains(parm.name)) {
                    unusedParms.remove(parm.name)
                    callableParms.put(parm, parmMap.get(parm.name))
                } else if (parm.kind == KParameter.Kind.VALUE) {
                    if (parm.isOptional) {
                        // default value will be used!
                    } else {
                       throw IllegalStateException("Missing required parameter ${parm.name}")
                    }
                } else {
                    throw IllegalStateException("Cannot call methods that are not direct instance methods")
                }
            }
            if (unusedParms.isNotEmpty()) {
                throw IllegalStateException("Unrecognized parameters passed to function: $unusedParms")
            }
            return method.kotlinFunction?.callBy(callableParms) as T
        }
    }
}

现在可以从 Java 中调用静态方法,但它并没有那么有趣。确实需要代码生成器。从 Kotlin 调用它要容易得多,并且一些框架(例如 Klutter 和 Kovert)已经使用了这些方法。

    Foo foo = new Foo();
    System.out.println(foo.bar("Frank"));

    Method barMethod = Foo.class.getMethod("bar", String.class);

    Map<String, Object> parms = new HashMap<String, Object>();

    parms.put("name", "David");
    System.out.println(KReflectHelper.callKotlinMethodWithNamedParms(foo, barMethod, parms));

    // now call using the default
    parms.clear();
    System.out.println(KReflectHelper.callKotlinMethodWithNamedParms(foo, barMethod, parms));

输出:

你好弗兰克!

大卫你好!

世界你好!

【讨论】:

    猜你喜欢
    • 2020-12-08
    • 2015-10-30
    • 2020-06-24
    • 1970-01-01
    • 2016-06-05
    • 1970-01-01
    • 2018-04-23
    • 2019-04-08
    相关资源
    最近更新 更多