Доступ до функцій розширення Kotlin від Java


157

Чи можливий доступ до функцій розширення з коду Java?

Я визначив функцію розширення у файлі Котліна.

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()метод, і компіляція не вдається.

Для чого використовується статична функція від kotlin:

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

використовуючи, import com.test.extensions.ExtensionsPackageтаким чином, мій IDE, здається, правильно налаштований.

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

Що я роблю неправильно? Це навіть можливо?


Будь ласка, детальніше про те, чи не працює ? Чи складається, викидає виняток, чи що? Також у вас є import package com.test.extensions.MyModel?
мескобалази

@meskobalazs дивіться мою відредаговану відповідь.
Ловіс

@meskobalazs, я навіть не можу це імпортувати. Я можу лише імпортуватиcom.test.extensions.ExtensionsPackage
Ловіс

Відповіді:


230

Усі функції Kotlin, задекларовані у файлі, будуть за замовчуванням скомпільовані статичними методами у класі в межах одного пакету та з ім'ям, отриманим із вихідного файлу Котліна (Перша літера з великим літери, а розширення ".kt" замінено на "Kt" суфіксом ) . Методи, створені для функцій розширення, матимуть додатковий перший параметр із типом приймача функції розширення.

Застосувавши його до оригінального питання, компілятор Java побачить вихідний файл Kotlin з назвою example.kt

package com.test.extensions

public fun MyModel.bar(): Int { /* actual code */ }

ніби оголошено наступний клас Java

package com.test.extensions

class ExampleKt {
    public static int bar(MyModel receiver) { /* actual code */ }
}

Оскільки з розширеним класом з точки зору Java нічого не відбувається, ви не можете просто використовувати точковий синтаксис для доступу до таких методів. Але вони все ще можуть називатися звичайними статичними методами Java:

import com.test.extensions.ExampleKt;

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

Статичний імпорт може бути використаний для класу ExampleKt:

import static com.test.extensions.ExampleKt.*;

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

1
Я зрозумів, це означає, що я не можу використовувати розширення від Kotlin до Java, якщо не напишу статичні функції?
AbdulMomen عبدالمؤمن

11
JFYI, Ви також можете змінити назву класу за допомогою @file: JvmName ("<TheNameThatYouWant> Utils").
crgarridos

3
що робити, якщо я створю розширення з параметрами?
AmirG

3
Параметри @AmirG будуть слідувати екземпляру. У цьому випадку це будеbar(model, param1, param2);
Тім

Це справді була швидка допомога, велике спасибі
Vivek Gupta

31

Функція розширення Kotlin верхнього рівня складена як статичні методи Java.

Дано файл Kotlin 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

У Котліні методи розширення можуть бути оголошені іншими способами. (Наприклад, як функція-член або як розширення супутнього об'єкта.)


8

У мене є файл Котліна під назвою 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());

6

Ви завжди можете побачити фактичний код Java, який генерується з коду Котліна, перейшовши на 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);

0

Вам потрібно дублювати свої функції у файлах класу:

Створіть файл Kotlin, для ex Utils.kt

Введіть код

  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);

0

Це працює для мене:

Котлін котлін

Код Java введіть тут опис зображення

Мій проект - це старий проект для Android, створений за допомогою Java; тепер я створив перший файл kotlin і додав розширення String весело String.isNotNullOrEmpty (): Boolean {...}

і я міг би викликати його з файлу Java за допомогою: StringUtilsKt.isNotNullOrEmpty (thestring).

Моє ім'я файлу kotlin - StringUtils


-1

Інші відповіді тут стосуються виклику функції розширення, розташованої на верхньому рівні файлу пакунків Kotlin.

Однак мій випадок полягав у тому, що мені потрібно було викликати функцію розширення, розташовану всередині класу. Зокрема, я мав справу з об’єктом.

Рішення неймовірно просте .

Все, що вам потрібно зробити, - це примітити свою функцію розширення як @JvmStaticі voila! Ваш код Java зможе отримати доступ до нього та використовувати його.


Чому потік? Моя відповідь правильна і оригінальна.
forresthopkinsa

-2

Коли ви продовжите такий клас:

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);
  }
}

Тут є більше прикладів .


-3

Наскільки я можу сказати, це неможливо. З мого читання документів про розширення виходить, що

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, оскільки компілятор просто побачить невідомий метод, який викликається об'єктом та виходить з помилки.


3
Ця відповідь не вірна, до них можна отримати доступ. Дивіться прийняту відповідь.
Джейсон Мінард

І компілятор не шукає статичних методів (особливо не статичних методів Java). Він шукає методи розширення, які були оголошені або імпортовані в одному файлі.
Кирило Рахман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.