简体   繁体   English

Kotlin方法重载

[英]Kotlin method overloading

This following declaration is legal in Kotlin. 以下声明在Kotlin中是合法的。

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

As bytecode we are getting: 作为字节码我们得到:

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

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

It's also possible to call both of these methods from Kotlin. 也可以从Kotlin调用这两种方法。

The problem comes when I'm trying to call any of them from Java: 当我试图从Java中调用其中任何一个时,问题出现了:

ClassKt.foo()

Ambiguous call. 暧昧的电话。 Both methods match ... 两种方法都匹配......

How to avoid such a problem? 如何避免这样的问题? How to deal with such methods? 如何处理这样的方法? What if 3-rd party kt library has same issue? 如果第三方kt库有同样的问题怎么办?

The example above is a synthetic one. 上面的例子是合成的例子。

Why does it work with Kotlin to begin with... In Java having two methods like: 为什么它与Kotlin一起开始...在Java中有两种方法,如:

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

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

would result in a compile time error. 会导致编译时错误。 And for java devs this is sort of obvious, these methods would have the same type erasure. 对于java devs来说,这很明显,这些方法将具有相同类型的擦除。 But this is rule imposed by javac , not by the JVM where this code runs. 但这是由javac强加的规则, 而不是由运行此代码的JVM强加的规则。 So javac does not treat two methods as having only a different return type as overloads. 因此, javac不会将两个方法视为具有不同的返回类型作为重载。 Well, kotlin is a different language and since it runs on the JVM (that expects valid byte-code) it allows treating methods with only the return type being different as overloads. 好吧, kotlin是一种不同的语言,因为它在JVM上运行(期望有效的字节码),它允许处理只有返回类型不同的方法作为重载。 I am yet to look at the byte code and understand how that happens; 我还没看看字节码并理解它是如何发生的; it also seems that this will work only for generic code, so may be type erasure is slightly different in case of kotlin. 似乎这只适用于通用代码,因此在kotlin的情况下类型擦除可能略有不同。

Now, things should be obvious why calling such a method from java fails. 现在,为什么从java调用这样的方法失败的事情应该是显而易见的。 Kotlin offers a neat solution for this: @JvmName("someDistinctName") . Kotlin为此提供了一个简洁的解决方案: @JvmName("someDistinctName") I am not entirely sure how this works under the hood either... yet, though I assume this will create a bridge method. 我不完全确定它是如何工作的......但是,尽管我认为这将创建一个桥接方法。

EDIT 编辑

@JvmName will rename the method at the byte-code level. @JvmName将在字节码级别重命名该方法。

You can use @JvmName to differentiate the code when it's called from java: 从java调用代码时,可以使用@JvmName来区分代码:

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

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

This will allow calling the String method in Java with ClassKt.fooString() , which resolves the clash. 这将允许使用ClassKt.fooString()调用Java中的String方法,该方法可以解决冲突。

An easy solution would be writing a helper method in Kotlin and just calling that. 一个简单的解决方案是在Kotlin中编写一个帮助方法,然后调用它。


Another way using only Java would be getting a MethodHandle for both methods and using them: 另一种只使用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();

It's not nearly as simple and requires handling exceptions though. 它不是那么简单,但需要处理异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM