Kotlin 方法重载

Kotlin method overloading

以下声明在 Kotlin 中是合法的。

fun foo(): String = "foo_1"
fun <T> foo(): T = "foo_2" as T

作为字节码,我们得到:

public final static foo()Ljava/lang/String;

// signature <T:Ljava/lang/Object;>()TT;
// declaration: T foo<T>()
public final static foo()Ljava/lang/Object;

也可以从 Kotlin 调用这两种方法。

当我试图从 Java:

调用其中任何一个时,问题就来了
ClassKt.foo()

Ambiguous call. Both methods match ...

如何避免这样的问题?如何处理这些方法?如果第 3 方 kt 库有同样的问题怎么办?

上面的例子是一个合成的例子。

你可以用@JvmName来区分调用时的代码java:

@JvmName("fooString")
fun foo(): String = "foo_1"

fun <T> foo(): T = "foo_2" as T

这将允许使用 ClassKt.fooString() 调用 Java 中的 String 方法,从而解决冲突。

为什么 它与 Kotlin 一起开始工作......在 Java 中有两种方法,如:

private static String test() {
    return "";
}

private static <T> T test() {
    return null;
}

会导致编译时错误。对于 java 开发者来说,这是显而易见的,这些方法将具有相同的类型擦除。 但是 这是 javac 强加的规则, 而不是 JVM 运行此代码的地方。因此 javac 不会将两种方法视为具有 只有 不同的 return 类型作为重载。好吧,kotlin 是一种不同的语言,因为它在 JVM 上运行(需要有效的字节码),所以它允许使用 only 处理方法 return 类型与重载不同。我还没有查看字节码并了解它是如何发生的;这似乎也只适用于通用代码,因此在 kotlin 的情况下,类型擦除可能略有不同。

现在,从 java 调用这样的方法失败的原因应该很明显了。 Kotlin 为此提供了一个简洁的解决方案:@JvmName("someDistinctName")。我也不完全确定它在幕后是如何工作的……但是,尽管我认为这将创建一个桥接方法。

编辑

@JvmName 将在字节码级别重命名该方法。

一个简单的解决方案是在 Kotlin 中编写一个辅助方法并调用它。


另一种仅使用 Java 的方法是为两种方法获取 MethodHandle 并使用它们:

MethodHandle MH_fooString = lookup().findStatic(ClassKt.class, "foo", methodType(String.class));
MethodHandle MH_fooT = lookup().findStatic(ClassKt.class, "foo", methodType(Object.class));

String foo = (String) MH_fooString.invokeExact();

它远没有那么简单,但需要处理异常。