Halo, Habr!
Hari ini kita akan membahas topik penting: interoperabilitas Jawa dan
Kotlin . Para penulis publikasi yang diusulkan beranggapan bahwa tidak mungkin untuk menulis ulang basis kode yang dibuat di Jawa ke Kotlin. Oleh karena itu, lebih tepat untuk memastikan interaksi kode Java dan Kotlin. Baca cara melakukannya dengan anotasi.
Saya pikir Anda membuka artikel ini karena alasan berikut:
- Akhirnya memutuskan untuk mencoba Kotlin.
- Anda menyukainya, yang, bagaimanapun, tidak mengejutkan.
- Memutuskan untuk menggunakan Kotlin di mana-mana
- Menghadapi kenyataan pahit: Jawa tidak bisa sepenuhnya ditinggalkan, setidaknya dengan sedikit darah.
Mengapa
Jika Kotlin sangat keren, mengapa tidak menggunakannya di mana-mana dan selalu? Di sini, begitu saja, beberapa skenario di mana ini tidak mungkin:
- Ketika Anda mencoba untuk perlahan mentransfer seluruh basis kode Anda ke Kotlin, Anda akan melihat bahwa ada file yang hanya menakutkan untuk menggunakan perintah
Convert Java to Kotlin file
. Jika Anda punya waktu untuk refactoring, lakukanlah! Namun, dalam proyek nyata, waktu untuk refactoring tidak selalu ditemukan. - Kode Anda akan digunakan oleh programmer yang bekerja dengan Java dan Kotlin. Anda tidak dapat (atau tidak seharusnya) memaksa mereka semua untuk menggunakan bahasa tertentu, terutama jika mendukung kedua bahasa tidak memerlukan banyak upaya dari Anda (tentu saja, saya berbicara tentang penjelasan).
Di sini kita melihat beberapa penjelasan yang menyediakan interoperabilitas antara Jawa dan Kotlin!
Anotasi JavaJvmfield- Apa yang dia lakukan Memberitahu kompiler Kotlin untuk tidak menghasilkan getter dan setter untuk properti ini dan menyediakannya sebagai bidang.
- Kasus praktis paling umum adalah menyediakan bidang objek pengiring.
Bagaimana cara kerjanya?
Misalkan Anda mendefinisikan bidang di dalam
object / companion object
di Kotlin:
object Constants { val PERMISSIONS = listOf("Internet", "Location") }
Jika Anda mencoba memanggil fungsi ini dari Jawa, Anda harus menulis:
Utils.INSTANCE.getPERMISSIONS()
Banyak kode untuk bidang sederhana! Untuk membuat kode lebih bersih, mari kita hilangkan kelebihan dengan menambahkan anotasi.
object Constants { @JvmField val PERMISSIONS = listOf("Internet", "Location") }
Sekarang kode Java kita akan terlihat seperti ini:
Utils.PERMISSIONS;
Hal yang sama dapat dicapai dengan pengubah, namun pengubah semacam itu hanya berfungsi dengan tipe atau string primitif.
Kapan anotasi ini tidak dapat digunakan?
Properti
const
ditandai sebagai dan fungsi tidak dapat dijelaskan dengan
@JvmField
Jvmstatic- Apa yang dia lakukan Jika digunakan dengan fungsi, ini menunjukkan bahwa metode statis tambahan harus dihasilkan dari elemen ini. Jika digunakan dengan properti, metode pengambil statis tambahan dan metode penyetel akan dihasilkan.
- Kasus praktis paling umum: menyediakan anggota (fungsi, properti) dari objek pendamping.
Bagaimana cara kerjanya?
Misalkan Anda mendefinisikan fungsi dalam
object
di Kotlin:
object Utils { fun doSomething(){ ... } }
Jika Anda mencoba memanggil fungsi ini dari Jawa, Anda harus menulis:
Utils.INSTANCE.doSomething()
Kita harus mengakses objek
INSTANCE
setiap kali kita ingin memanggil fungsi ini. Untuk membuat kode lebih bersih, mari kita gunakan anotasi
@JvmStatic
.
object Utils { @JvmStatic fun doSomething(){ ... } }
Sekarang, memanggil fungsi ini dari Jawa, kita hanya perlu menulis:
Utils.doSomething();
Jauh lebih baik, bukan? Situasi ini seolah-olah fungsi awalnya ditulis dalam Java sebagai metode statis.
Anotasi juga dapat diterapkan ke bidang:
object Utils { @JvmStatic var values = listOf("Test 1", "Test 2") }
Memanggil kode ini dari Jawa, Anda dapat menulis:
Utils.getValues();
Catatan:
JvmField
menyediakan anggota sebagai bidang, tetapi dengan
JvmStatic
kami menyediakan fungsi
get
.
Dan karena bidangnya adalah
var
, metode yang
set
juga dihasilkan:
Utils.setValues(...);
Jika kita memiliki konstanta di dalam objek kita, maka kita juga dapat mendeklarasikannya sebagai statis:
object Utils { @JvmStatic val KEY = "test" }
Namun, dalam hal ini, menggunakan anotasi bukan ide yang baik, karena doa permohonan akan terlihat seperti ini:
public void foo(){ String key = Utils.getKEY(); }
Dalam hal ini, gunakan mod modifier atau JvmField, seperti yang dijelaskan di atas.
Kapan itu tidak bisa digunakan?
Anggota tidak dapat dianotasi dengan JvmStatic ketika diikuti oleh pengubah
open
,
override
atau
const
.
Dalam situasi ini, kode tidak mengkompilasi:
JvmOverloads- Apa yang dia lakukan Memberitahu kompiler Kotlin untuk menghasilkan kelebihan fungsi ini, yang menggantikan nilai parameter default.
- Apa itu kelebihan beban? Di Kotlin, fungsi Anda mungkin memiliki parameter default, sehingga Anda dapat memanggil fungsi yang sama dengan cara yang berbeda. Untuk mencapai hal yang sama di Java, Anda harus secara manual menentukan setiap variasi individual dari fungsi ini. Masing-masing variasi yang dihasilkan secara otomatis ini disebut "overload". Kasus penggunaan yang paling umum: konstruktor kelas yang berlebihan. Ya, teknik ini berfungsi dengan fungsi apa pun yang memiliki pengaturan default.
Bagaimana cara kerjanya?
Jika Anda memiliki kelas dengan konstruktor (atau fungsi lainnya) dengan parameter default ...
class User constructor ( val name: String = "Test", val lastName: String = "Testy", val age: Int = 0 )
... maka Anda dapat memanggil fungsi seperti itu dari Kotlin dengan berbagai cara:
val user1 = User() val user2 = User(name = "Bruno") val user3 = User(name = "Bruno", lastName = "Aybar") val user4 = User(name = "Bruno", lastName = "Aybar", age = 21) val user5 = User(lastName = "Aybar") val user6 = User(lastName = "Aybar", age = 21) val user7 = User(age = 21) val user8 = User(age = 21, name = "Bruno") ...
Namun, jika Anda mencoba memanggil konstruktor dari Java, Anda hanya akan memiliki dua opsi: 1) meneruskan semua parameter atau 2) hanya jika SEMUA parameter Anda memiliki nilai default, Anda tidak dapat melewati parameter apa pun.
Jika kita ingin membuat kelebihan, kita dapat menggunakan anotasi
JvmOverloads
:
class User @JvmOverloads constructor ( val name: String = "Test", val lastName: String = "Testy", val age: Int = 0 )
Sekarang ketika menggunakan Java, kami memiliki banyak peluang:

Namun, di Kotlin tidak ada banyak pilihan dalam hal ini. Misalnya, kita tidak akan dapat hanya melewati nama belakang atau hanya usia.
JvmOverloads
hanya
JvmOverloads
menghasilkan banyak kelebihan karena fungsi memiliki parameter default.
- Jika Anda memiliki fungsi, Anda dapat menandainya sebagai
JvmOverload
. Anda bahkan dapat menggabungkannya dengan anotasi lain, misalnya, dengan JvmStatic
. - Kapan sebaiknya Anda tidak menggunakannya? Anotasi ini tidak berguna jika fungsi tidak memiliki parameter default.
file : JvmName- Apa yang dia lakukan Menentukan nama untuk kelas Java atau metode yang dihasilkan dari elemen ini.
- Kasus yang paling umum: berikan nama yang lebih indah ke file Kotlin. Namun, anotasi ini berlaku tidak hanya dengan file, tetapi juga dengan fungsi, serta dengan metode untuk mengakses properti (getter dan setter).
Bagaimana cara kerjanya?
Di Kotlin, di mana fungsi adalah elemen istimewa, Anda bisa menulis fungsi yang ada di luar kelas. Misalnya, jika Anda membuat file Kotlin baru dan menulis kode berikut, maka ia dikompilasi tanpa masalah:
//file name: Utils.kt fun doSomething() { ... }
Anda dapat memanggil kode ini dari Jawa:
UtilsKt.doSomething();
Harap dicatat: meskipun file tersebut disebut Utils, panggilan tersebut menggunakan nama
UtilsKt
, yang tidak ideal. Untuk memperbaikinya, mari kita tambahkan anotasi
JvmName
di atas file.
// : Utils.kt @file:JvmName("Utils") fun doSomething() { ... }
Perhatikan bagaimana
file:
awalan digunakan. Anda mungkin menebaknya: ini menunjukkan bahwa anotasi yang kami gunakan diterapkan pada level file. Jika Anda memanggil kode berikut dari Jawa:
Utils.doSomething();
Anda juga dapat membuat anotasi fungsi:
// : Utils.kt @file:JvmName("Utils") @JvmName("doSomethingElse") fun doSomething() { ... }
Saat memanggil kode ini dari Kotlin, kami masih akan menggunakan nama asli (
doSomething
), tetapi di Jawa kami menggunakan nama yang ditentukan dalam anotasi:
//Java Utils.doSomethingElse(); //Kotlin Utils.doSomething()
Fitur ini tampaknya tidak terlalu berguna, namun dapat digunakan untuk menyelesaikan konflik tanda tangan. Skrip ini dipahami dengan baik dalam
dokumentasi resmi .
Di sini Anda dapat bekerja dengan metode untuk mengakses properti:
class User { val likesKotlin: Boolean = true @JvmName("likesKotlin") get() = field }
Lihat bagaimana panggilan ini akan terlihat di Jawa dengan dan tanpa anotasi:
// new User().getLikesKotlin() // new User().likesKotlin()
Hal yang sama dapat dicapai dengan awalan
get
.
class User { @get:JvmName("likesKotlin") val likesKotlin = true }
- Kapan saya bisa menggunakan kesempatan ini? Dengan file, fungsi, metode untuk mengakses properti. Namun, pastikan untuk meletakkan awalan yang diperlukan jika perlu.
- Kapan sebaiknya Anda tidak menggunakannya? Jika Anda secara acak mengatur fungsi nama alternatif, Anda dapat membuat banyak kebingungan. Gunakan anotasi ini dengan cermat, dan jika Anda melamar, maka gunakan secara konsisten.
Saya harap Anda menemukan ikhtisar penjelasan ini berguna, membantu Anda menulis kode di Kotlin yang mudah digunakan dengan Java.