Mengakses fungsi ekstensi Kotlin dari Jawa

157

Apakah mungkin untuk mengakses fungsi ekstensi dari kode Java?

Saya mendefinisikan fungsi ekstensi dalam file Kotlin.

package com.test.extensions

import com.test.model.MyModel

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

Di mana MyModelkelas java (dihasilkan). Sekarang, saya ingin mengaksesnya dalam kode java normal saya:

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

Namun, itu tidak berhasil. IDE tidak akan mengenali bar()metode dan kompilasi gagal.

Apa yang berhasil digunakan dengan fungsi statis dari kotlin:

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

dengan menggunakan import com.test.extensions.ExtensionsPackageIDE saya sepertinya sudah terkonfigurasi dengan benar.

Saya mencari melalui seluruh file Java-interop dari dokumen kotlin dan juga banyak googled, tetapi saya tidak dapat menemukannya.

Apa yang saya lakukan salah? Apakah ini mungkin?

Lovis
sumber
Tolong uraikan tidak berfungsi ? Apakah itu mengkompilasi, melempar pengecualian, atau apa? Anda juga import package com.test.extensions.MyModel?
meskobalazs
@meskobalazs melihat jawaban saya yang diedit.
Lovis
@meskobalazs juga, saya bahkan tidak bisa mengimpor itu. Saya hanya dapat mengimporcom.test.extensions.ExtensionsPackage
Lovis

Jawaban:

230

Semua fungsi Kotlin yang dideklarasikan dalam file akan dikompilasi secara default ke metode statis di kelas dalam paket yang sama dan dengan nama yang berasal dari file sumber Kotlin (huruf kapital pertama dan ekstensi ".kt" diganti dengan akhiran "Kt" ) . Metode yang dihasilkan untuk fungsi ekstensi akan memiliki parameter pertama tambahan dengan jenis penerima fungsi ekstensi.

Menerapkannya ke pertanyaan awal, kompiler Java akan melihat file sumber Kotlin dengan nama example.kt

package com.test.extensions

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

seolah-olah kelas Java berikut dideklarasikan

package com.test.extensions

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

Karena tidak ada yang terjadi dengan kelas yang diperluas dari sudut pandang Java, Anda tidak bisa hanya menggunakan sintaks dot untuk mengakses metode tersebut. Tetapi mereka masih bisa dipanggil sebagai metode statis Java normal:

import com.test.extensions.ExampleKt;

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

Impor statis dapat digunakan untuk kelas ExampleKt:

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

MyModel model = new MyModel();
bar(model);
selamat tinggal
sumber
1
Saya mengerti, artinya saya tidak dapat menggunakan ekstensi dari Kotlin ke Java kecuali saya menulis fungsi statis?
AbdulMomen عبدالمؤمن
11
JFYI, Anda juga dapat mengubah nama kelas dengan @file: JvmName ("<TheNameThatYouWant> Utils").
crgarridos
3
bagaimana jika saya membuat ekstensi dengan parameter?
AmirG
3
Parameter @AmirG akan mengikuti instance. Dalam hal ini adalahbar(model, param1, param2);
Tim
Ini benar-benar bantuan cepat, Terima kasih banyak
Vivek Gupta
31

Fungsi ekstensi tingkat atas Kotlin dikompilasi sebagai metode statis Java.

File Kotlin yang diberikan Extensions.ktdalam paket foo.barberisi:

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

Kode Java yang setara adalah:

package foo.bar;

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

Kecuali, jika ada, Extensions.ktmengandung garis

@file:JvmName("DemoUtils")

Dalam hal ini kelas statis Java akan dinamai DemoUtils

Di Kotlin, metode ekstensi dapat dideklarasikan dengan cara lain. (Misalnya, sebagai fungsi anggota atau sebagai perpanjangan dari objek pendamping.)

Aleksandr Dubinsky
sumber
8

Saya memiliki file Kotlin bernama NumberFormatting.kt yang memiliki fungsi sebagai berikut

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

Di java saya sederhana mengaksesnya melalui file NumberFormattingKt dengan cara berikut setelah impor diperlukan import ....extensions.NumberFormattingKt;

String literString = NumberFormattingKt.formattedFuelAmountString(item.getAmount());
Ilker Baltaci
sumber
6

Anda selalu dapat melihat kode Java aktual yang dihasilkan dari kode Kotlin Anda dengan membuka Tools > Kotlin > Show Kotlin Bytecode, lalu mengklik Decompile. Ini dapat sangat membantu Anda. Dalam kasus Anda, kode Java akan terlihat seperti ini jika adaMyModelExtensions.kt

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

Anda dapat memperbaikinya dengan menggunakan @JvmNamefile yang berisi bar:

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

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

dan itu akan menghasilkan kode ini:

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

Penggunaan MyModelssesuai dengan apa yang disarankan Java Efektif untuk kelas utilitas. Anda juga dapat mengubah nama metode Anda seperti ini:

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

kemudian dari sisi Jawa akan terlihat idiomatis:

MyModels.extractBar(model);
Adam Arold
sumber
0

Anda perlu menduplikasi fungsi Anda di file kelas:

Buat file Kotlin, untuk ex Utils.kt

Masukkan kodenya

  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
        }

ATAU

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
}

Dalam penggunaan kotlin:

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

Di Jawa gunakan ini:

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

Ini bekerja untuk saya:

Kotlin kotlin

Kode Java masukkan deskripsi gambar di sini

Proyek saya adalah proyek android lama yang dibuat dengan Java; sekarang saya membuat file kotlin pertama dan menambahkan String extensions fun String.isNotNullOrEmpty (): Boolean {...}

dan saya bisa menyebutnya dari file java menggunakan: StringUtilsKt.isNotNullOrEmpty (thestring).

Nama file kotlin saya adalah StringUtils

Cristian Díez
sumber
-1

Jawaban lain di sini mencakup kasus memanggil fungsi ekstensi yang terletak di bagian atas file paket Kotlin.

Namun, kasus saya adalah bahwa saya perlu memanggil fungsi Extension yang terletak di dalam Kelas. Secara khusus, saya berurusan dengan sebuah Object.

Solusinya sangat sederhana .

Yang harus Anda lakukan adalah membubuhi keterangan fungsi ekstensi Anda sebagai @JvmStatic, dan voila! Kode Java Anda akan dapat mengaksesnya dan menggunakannya.

forresthopkinsa
sumber
Mengapa downvote? Jawaban saya benar dan asli.
forresthopkinsa
-2

Ketika Anda memperluas kelas seperti ini:

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

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

Ini akan dikompilasi untuk ini:

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

Ada lebih banyak contoh di sini .

Tomas Bjerre
sumber
-3

Sejauh yang saya tahu ini tidak mungkin. Dari pembacaan saya tentang ekstensi dokumen, tampaknya itu

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

menciptakan metode baru dengan tanda tangan

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

Kemudian, Kotlin memetakan yang berfungsi untuk panggilan formulir myModel.bar(), di mana jika bar()tidak ditemukan di MyModelkelas itu mencari metode statis yang cocok dengan tanda tangan dan skema penamaan yang dihasilkannya. Perhatikan bahwa ini hanya asumsi dari pernyataan mereka tentang ekstensi yang diimpor secara statis dan tidak mengabaikan metode yang ditentukan. Saya belum mendapatkan sumber yang cukup jauh untuk mengetahui dengan pasti.

Jadi, dengan asumsi di atas benar tidak ada cara untuk ekstensi Kotlin dipanggil dari kode java lama, karena kompiler hanya akan melihat metode yang tidak diketahui dipanggil pada objek dan kesalahan keluar.

johnw188
sumber
3
Jawaban ini tidak benar, mereka dapat diakses. Lihat jawaban yang diterima.
Jayson Minard
Dan kompiler tidak mencari metode statis (terutama bukan metode statis Java). Sedang mencari metode ekstensi yang telah dinyatakan atau diimpor dalam file yang sama.
Kirill Rakhman