Перегрузка методом Котлина - PullRequest
0 голосов
/ 25 августа 2018

Это следующее объявление является допустимым в 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()

Неоднозначный вызов.Оба метода совпадают ...

Как избежать такой проблемы?Как бороться с такими методами?Что, если у сторонней библиотеки kt такая же проблема?

Пример выше - синтетический.

Ответы [ 3 ]

0 голосов
/ 25 августа 2018

Почему работает с Kotlin с самого начала ... В Java наличие двух методов, таких как:

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

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

, приведет к ошибке времени компиляции.И для разработчиков Java это вроде очевидно, эти методы будут иметь стирание одного и того же типа. Но это правило, налагаемое javac, , а не на JVM, где выполняется этот код.Таким образом, javac не рассматривает два метода как имеющие только другого возвращаемого типа в качестве перегрузок.Ну, kotlin - это другой язык, и поскольку он работает на JVM (который ожидает действительный байт-код), он позволяет обрабатывать методы только с * , тип возвращаемого значения отличается от перегрузок.Мне еще предстоит взглянуть на байт-код и понять, как это происходит;также кажется, что это будет работать только для общего кода, поэтому стирание типов может немного отличаться в случае kotlin.

Теперь должно быть очевидно, почему не удается вызвать такой метод из Java.Для этого Котлин предлагает удобное решение: @JvmName("someDistinctName").Я не совсем уверен, как это работает под капотом либо ... пока, хотя я предполагаю, что это создаст метод моста.

EDIT

@JvmName будетпереименуйте метод на уровне байт-кода.

0 голосов
/ 26 августа 2018

Простым решением было бы написать вспомогательный метод в 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();

Это не так просто и требует обработки исключений.

0 голосов
/ 25 августа 2018

Вы можете использовать @ JvmName , чтобы отличить код при вызове от java:

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

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

Это позволит вызывать метод String в Java с ClassKt.fooString(), который разрешает конфликт.

...