Доступ к функциям расширения Kotlin с Java



можно ли получить доступ к функциям расширения из кода Java?



Я определил функцию расширения в файле Kotlin.



package com.test.extensions

import com.test.model.MyModel

/**
*
*/
public fun MyModel.bar(): Int {
return this.name.length()
}


здесь MyModel - это (сгенерированный) класс java.
Теперь я хотел получить доступ к нему в своем обычном java-коде:



MyModel model = new MyModel();
model.bar();


однако, это не работает. IDE не распознает bar() метод и компиляция не удается.



что работает использует со статической функцией от Котлин:



public fun bar(): Int {
return 2*2
}


С помощью import com.test.extensions.ExtensionsPackage так что моя IDE, кажется, настроена правильно.



Я искал весь файл Java-interop из документов kotlin, а также много гуглил, но я не мог его найти.



что я делаю не так? Это вообще возможно?

876   8  

8 ответов:

все функции Kotlin, объявленные в файле, будут скомпилированы по умолчанию в статические методы в классе в том же пакете и с именем, полученным из исходного файла Kotlin (первая буква заглавная и ".КТ"

функция расширения верхнего уровня Kotlin компилируется как статические методы Java.

учитывая файл Котлина Extensions.kt в пакете foo.bar содержит:

fun String.bar(): Int {
    ...
}

эквивалентный код Java будет:

package foo.bar;

class ExtensionsKt {
    public static int bar(String receiver) { 
        ...
    }
}

если Extensions.kt содержит строку

@file:JvmName("DemoUtils")

в этом случае статический класс java будет называться DemoUtils

в Kotlin методы расширения могут быть объявлены другими способами. (Например, как функция-член или как расширение сопутствующего объекта.) Я постараюсь расширить этот ответ на более поздний срок.

вам нужно дублировать ваши функции в файлах класса:

создать файл Kotlin, например Utils.КТ

ввести код

  class Utils {
                companion object {
                    @JvmStatic
                    fun String.getLength(): Int {//duplicate of func for java
                        return this.length
                    }
                }
            }

        fun String.getLength(): Int {//kotlin extension function
            return this.length
        }

или

class Utils {
    companion object {

        @JvmStatic
        fun getLength(s: String): Int {//init func for java
            return s.length
        }
    }
}

fun String.getLength(): Int {//kotlin extension function
    return Utils.Companion.getLength(this)//calling java extension function in Companion
}

В использовать Котлин:

val str = ""
val lenth = str.getLength()

в Java используйте это:

String str = "";
 Integer lenth = Utils.getLength(str);

у меня есть файл Kotlin под названием NumberFormatting.kt, который имеет следующую функцию

fun Double.formattedFuelAmountString(): String? {
    val format = NumberFormat.getNumberInstance()
    format.minimumFractionDigits = 2
    format.maximumFractionDigits = 2
    val string = format.format(this)
    return string
}

в java я просто получить доступ к нему через файл NumberFormattingKt следующим образом: после необходимого импорта import ....extensions.NumberFormattingKt;

String literString = NumberFormattingKt.formattedFuelAmountString(item.getAmount());

вы всегда можете увидеть фактический Java-код, который генерируется из вашего кода Kotlin, перейдя в Tools > Kotlin > Show Kotlin Bytecode, затем нажать Decompile. Это может вам очень помочь. В вашем случае код Java будет выглядеть так, если у вас есть MyModelExtensions.kt

public final class MyModelExtensionsKt {
   public static final int bar(@NotNull MyModel $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      return $receiver.getName().length();
   }
}

вы можете улучшить с помощью @JvmName на файл, содержащий bar:

@file:JvmName("MyModels")
package io.sspinc.datahub.transformation

public fun MyModel.bar(): Int {
    return this.name.length
}

и это приведет к следующему коду:

public final class MyModels {
   public static final int bar(@NotNull MyModel $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      return $receiver.getName().length();
   }
}

используя MyModels в соответствии с Эффективная Java предлагает для служебных классов. Вы также можете переименовать свой метод следующим образом:

public fun MyModel.extractBar(): Int {
    return this.name.length
}

тогда со стороны Java это будет выглядеть идиоматично:

MyModels.extractBar(model);

насколько я могу судить, это невозможно. Из моего чтения документов расширений, похоже, что

public fun MyModel.bar(): Int {
    return this.name.length()
}

создает новый метод с подписью

public static int MyModelBar(MyModel obj) {
    return obj.name.length();
}

затем Котлин сопоставляет эту функцию с вызовами формы myModel.bar(), Если bar() не найден в MyModel класс он ищет статические методы, соответствующие сигнатуре и схеме именования, которую он выводит. обратите внимание, что это всего лишь предположение из их заявлений о расширении статически импортированные и не переопределяющие определенные методы. Я не настолько далеко продвинулся в их источнике, чтобы знать наверняка.

Итак, предполагая, что вышеизложенное верно, расширения Kotlin не могут быть вызваны из простого старого кода java, так как компилятор просто увидит, что неизвестный метод вызывается на объект и ошибка.

другие ответы здесь охватывают случай вызова функции расширения, расположенной на верхнем уровне файла пакета Kotlin.

однако в моем случае мне нужно было вызвать функцию расширения, расположенную внутри класса. В частности, я имел дело с объектом.

решение невероятно прост.

все, что вам нужно сделать, это аннотировать функцию расширения как @JvmStatic и вуаля! Ваш Java-код сможет получить к нему доступ и использовать оно.

когда вы расширяете класс, как это:

fun String.concatenatedLength(str: String): Int {
    return (this.length + str.length)
}

fun f() {
    var len = "one string".concatenatedLength("another string")
    println(len)
}

Он будет компилироваться на это:

import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

public final class ExampleKt {
  public static final int concatenatedLength(@NotNull String $receiver, @NotNull String str) {
    Intrinsics.checkParameterIsNotNull((Object) $receiver, (String) "$receiver");
    Intrinsics.checkParameterIsNotNull((Object) str, (String) "str");
    return $receiver.length() + str.length();
  }

  public static final void f() {
    int len = ExampleKt.concatenatedLength("one string", "another string");
    System.out.println(len);
  }
}

есть еще вот примеры:.

Comments

    Ничего не найдено.