object adalah deklarasi yang sekaligus mendefinisikan sebuah kelas dan satu-satunya instansnya. Kotlin menyediakan bentuk ini untuk menggantikan pola singleton yang biasanya ditulis manual pada bahasa lain. Topik ini membahas deklarasi object dengan state miliknya sendiri, waktu inisialisasinya, dan ekspresi object yang membuat instans sekali pakai tanpa kelas bernama. Contoh yang dipakai adalah registri sesi sederhana beserta dua pengubah teks.
Deklarasi object sebagai singleton#
Object dinyatakan dengan kata kunci object diikuti nama dan badan kelasnya. Tidak ada sintaks pemanggilan konstruktor, karena instansnya sudah tersedia begitu nama itu dipakai. Seluruh kode program mengacu pada instans yang sama, sehingga state yang tersimpan di dalamnya konsisten dari titik mana pun ia diubah. Deklarasi object juga dapat mengimplementasikan interface dengan menuliskan supertipenya setelah titik dua, sehingga satu-satunya instans tersebut tetap dapat diarahkan ke tipe yang lebih umum.
interface PengubahTeks {
fun ubah(teks: String): String
}
object RegistriSesi {
private val sesiAktif = mutableListOf<String>()
init {
println("RegistriSesi siap digunakan")
}
fun masuk(nama: String) {
sesiAktif.add(nama)
}
fun keluar(nama: String) {
sesiAktif.remove(nama)
}
fun jumlahAktif(): Int = sesiAktif.size
}
fun main() {
RegistriSesi.masuk("Ali")
RegistriSesi.masuk("Budi")
println("Sesi aktif: ${RegistriSesi.jumlahAktif()}")
RegistriSesi.keluar("Ali")
println("Sesi aktif: ${RegistriSesi.jumlahAktif()}")
val kapitalis = object : PengubahTeks {
override fun ubah(teks: String): String = teks.uppercase()
}
val pembalik = object : PengubahTeks {
override fun ubah(teks: String): String = teks.reversed()
}
println(kapitalis.ubah("kotlin"))
println(pembalik.ubah("kotlin"))
}# atur PATH compiler Kotlin dan lokasi kotlin-stdlib
export PATH=/home/kal/my-project/tools/kotlinc/bin:/home/kal/my-project/tools/jdk-merged/bin:$PATH
export STDLIB=/home/kal/my-project/tools/kotlinc/lib/kotlin-stdlib.jar
# kompilasi main.kt menjadi out.jar
kotlinc main.kt -d out.jar
# jalankan program dengan kotlin-stdlib di classpath
java -cp "out.jar:$STDLIB" MainKtRegistriSesi siap digunakan
Sesi aktif: 2
Sesi aktif: 1
KOTLIN
niltokFungsi main memanggil RegistriSesi seperti memanggil fungsi pada sebuah instans, padahal tidak ada instans yang dibuat secara manual. Nilai sesiAktif bertahan di antara pemanggilan, sehingga jumlah sesi aktif bergerak dari dua ke satu mengikuti operasi masuk dan keluar. Baris RegistriSesi siap digunakan muncul tepat satu kali dan menjadi petunjuk tentang waktu inisialisasi object.
Waktu inisialisasi object#
Deklarasi object tidak diinisialisasi ketika program dimulai, melainkan ketika akses pertama terjadi. Pada program di atas, pesan dari blok init muncul sebelum keluaran masuk yang pertama, karena pemanggilan RegistriSesi.masuk itulah yang memicu pembuatan instans. Karena hanya ada satu instans, inisialisasi hanya berlangsung sekali sepanjang hidup program.
Kotlin menjamin inisialisasi ini aman terhadap akses serentak. Meskipun beberapa thread menyentuh object yang sama pada saat yang bersamaan, inisialisasinya tetap berlangsung satu kali karena mekanisme pemuatan kelas pada JVM yang mendasarinya sudah mengatur hal tersebut. Bila program memuat beberapa object, masing-masing memiliki waktu inisialisasi sendiri sesuai akses pertamanya, sehingga biaya pemuatan tersebar dan tidak terpusat di awal program.
Pesan pada blok init tidak terulang pada akses kedua karena instansnya sudah ada. Konsekuensinya, pekerjaan berat yang diletakkan di blok init baru terasa pada akses pertama. Bila penundaan itu tidak diinginkan, sentuh object lebih awal atau ringankan isi blok init.
Ekspresi object#
Deklarasi object mengikat satu instans pada sebuah nama yang dapat dipakai di seluruh program. Bentuk kedua, yaitu ekspresi object, membuat instans tanpa nama di tempat ekspresi ditulis. Penulisannya berupa kata kunci object diikuti supertipe yang diimplementasikan, tanpa nama kelas sama sekali. Instans yang dihasilkan hidup selama variabel penampungnya, sehingga bentuk ini tepat untuk implementasi yang dipakai sekali di satu tempat, misalnya penangan sekali pakai atas sebuah interface.
Program di atas membuat dua ekspresi object untuk interface PengubahTeks. Yang pertama memperbesar huruf, yang kedua membalik urutan karakter, dan keduanya siap dipakai tanpa kelas bernama. Setiap kali ekspresi object dievaluasi, instans baru dibuat, berbeda dengan deklarasi object yang selalu mengembalikan instans yang sama. Sebuah ekspresi object dapat mengimplementasikan lebih dari satu interface sekaligus dan dapat mewarisi sebuah kelas dengan memanggil konstruktornya. Ekspresi object yang didefinisikan di dalam fungsi juga dapat membaca variabel lokal fungsi tersebut, sehingga perilakunya dapat disesuaikan dengan data di sekitarnya.
| Aspek | Deklarasi object | Ekspresi object |
|---|---|---|
| Nama | Wajib, menjadi titik akses global | Tanpa nama, diakses lewat variabel |
| Jumlah instans | Satu untuk seluruh program | Baru setiap ekspresi dievaluasi |
| Waktu inisialisasi | Akses pertama pada namanya | Saat ekspresi dievaluasi |
| Kegunaan lazim | Registri, konfigurasi, utilitas | Implementasi interface sekali pakai |
Hal yang perlu diperhatikan#
Deklarasi object tidak memiliki konstruktor, sehingga tidak ada cara mengirimkan parameter pembentukan kepadanya. Bila pembentukan memerlukan parameter, gunakan kelas biasa dengan konstruktornya, atau kelola parameter sebagai properti yang diatur setelahnya. Instans object juga tidak dapat dibuat ulang, karena tidak ada sintaks pemanggilan konstruktor untuknya. Deklarasi object pun tidak boleh diletakkan langsung di dalam fungsi, dan compiler menolaknya dengan pesan named object cannot be local, sedangkan ekspresi object memang diperuntukkan bagi posisi tersebut. Object yang dinyatakan di dalam sebuah kelas berjumlah satu untuk seluruh instans kelas itu, bukan satu per instans.
State yang tersimpan pada object bersifat global bagi seluruh program. Sifat ini nyaman untuk registri dan konfigurasi, tetapi menyulitkan pengujian karena satu pengujian dapat memengaruhi pengujian lain melalui state yang tersisa. Karena itu, batasi state yang dapat berubah pada object, dan pastikan fungsi-fungsinya tetap dapat dipanggil ulang tanpa saling mengganggu. Bila kebutuhan akan instans berparameter atau instans terpisah per pengujian muncul, kelas biasa merupakan pilihan yang lebih tepat.
Ringkasan#
objectmendefinisikan kelas dan satu-satunya instansnya sekaligus, dengan anggota yang diakses langsung lewat namanya.- Inisialisasi berlangsung saat akses pertama, dijamin satu kali, dan aman terhadap akses serentak dari beberapa thread.
- Ekspresi object membuat instans tanpa nama yang mengimplementasikan interface atau mewarisi kelas, tepat untuk pemakaian sekali di satu tempat.
- Deklarasi object tidak memiliki konstruktor dan state-nya bersifat global, sehingga perlu dijaga tetap ringan dan mudah diuji.
Referensi#
- Object declarations — Kotlin Documentation — Deklarasi object, ekspresi object, dan companion object pada dokumentasi resmi Kotlin.