Доступ к функциям расширения 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, а также много гуглил, но я не мог его найти.
что я делаю не так? Это вообще возможно?
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.ktpublic 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