11

以下声明在 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()

暧昧的呼唤。两种方法都匹配...

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

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

4

3 回答 3

10

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

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

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

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

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

编辑

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

于 2018-08-25T20:24:44.120 回答
2

当从 java 调用代码时,您可以使用@JvmName来区分代码:

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

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

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

于 2018-08-25T19:57:57.607 回答
1

一个简单的解决方案是在 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();

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

于 2018-08-25T21:13:23.423 回答