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();
它远没有那么简单,但需要处理异常。
以下声明在 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();
它远没有那么简单,但需要处理异常。