Reflection adalah mekanisme membaca struktur kode saat program berjalan. Kotlin menyediakan library kotlin.reflect yang berisi tipe KClass, KFunction, dan KProperty — padanan Class, Method, dan Field di Java reflection, tetapi lebih kaya informasi Kotlin. Pada chapter ini kita akan membahas cara mendapatkan KClass, properti penting yang dimilikinya, serta interop dengan Java reflection. Pemahaman ini menjadi fondasi sebelum membahas inspeksi class dan property pada chapter berikutnya.
Tiga Tipe Utama #
| Tipe | Padanan Java | Kegunaan |
|---|---|---|
KClass<T> | Class<T> | Mewakili class atau object Kotlin. |
KFunction<R> | Method / Constructor | Mewakili function, method, atau constructor. |
KProperty<V> | Field + getter/setter | Mewakili property (val atau var). |
Selain ketiganya, ada KParameter, KType, KCallable, dan lain-lain. Semua berada di package kotlin.reflect dan kotlin.reflect.full.
Mendapatkan KClass #
Ada dua cara untuk mendapatkan KClass:
val a: KClass<String> = String::class // literal ::class
val b: KClass<out String> = "halo"::class // instance::class (subtype)Literal String::class menghasilkan KClass<String>, sementara "halo"::class menghasilkan KClass<out String> (subtype karena instance bisa saja subtype dari String yang dideklarasikan).
Contoh Kode #
// File: kotlin_reflection.kt
// Mendemonstrasikan dasar-dasar Kotlin reflection: KClass, KFunction, KProperty.
package com.example.refleksi
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
import kotlin.reflect.KProperty
import kotlin.reflect.full.memberFunctions
import kotlin.reflect.full.memberProperties
data class Buku(val judul: String, val penulis: String, val tahun: Int) {
fun ringkas(): String = "$judul oleh $penulis ($tahun)"
}
fun sapa(nama: String): String = "Halo, $nama!"
fun infoBuku(kelas: KClass<Buku>) {
println("simpleName: ${kelas.simpleName}")
println("qualifiedName: ${kelas.qualifiedName}")
println("isData: ${kelas.isData}")
println("isSealed: ${kelas.isSealed}")
println("constructors: ${kelas.constructors.size}")
println("members: ${kelas.members.size}")
}
fun daftarFungsiMember(kelas: KClass<Buku>) {
println("\nDaftar function member (5 pertama):")
for (fn in kelas.memberFunctions.take(5)) {
println(" - ${fn.name} (params=${fn.parameters.size})")
}
}
fun daftarProperti(kelas: KClass<Buku>) {
println("\nDaftar property member:")
for (p in kelas.memberProperties) {
println(" - ${p.name}: ${p.returnType}")
}
}
fun main() {
// Cara mendapat KClass: literal ::class atau instance::class.
val kelasLiteral: KClass<Buku> = Buku::class
val kelasInstance: KClass<out Buku> = Buku("Halo", "Budi", 2026)::class
println("kelasLiteral: ${kelasLiteral.qualifiedName}")
println("kelasInstance: ${kelasInstance.qualifiedName}")
infoBuku(kelasLiteral)
daftarFungsiMember(kelasLiteral)
daftarProperti(kelasLiteral)
// Interop dengan Java reflection.
val javaClass = kelasLiteral.java
println("\nJava class: ${javaClass.name}")
println("Java isRecord: ${javaClass.isRecord}")
// Demonstrasi KFunction: reference ke top-level function.
val fnSapa: KFunction<String> = ::sapa
println("\nKFunction: ${fnSapa.name}, param count=${fnSapa.parameters.size}")
println("fnSapa.call(\"Budi\") = ${fnSapa.call("Budi")}")
// Demonstrasi KProperty: reference ke property Buku.judul.
val judulProp: KProperty<String> = Buku::judul
val buku = Buku("Kotlin Dasar", "Siti", 2025)
println("judulProp.getter.call(buku) = ${judulProp.getter.call(buku)}")
// KFunction pada member function (unbound).
val ringkasFn: KFunction<String> = Buku::ringkas
println("ringkasFn.call(buku) = ${ringkasFn.call(buku)}")
}Output yang Dihasilkan:
kelasLiteral: com.example.refleksi.Buku
kelasInstance: com.example.refleksi.Buku
simpleName: Buku
qualifiedName: com.example.refleksi.Buku
isData: true
isSealed: false
constructors: 1
members: 11
Daftar function member (5 pertama):
- component1 (params=1)
- component2 (params=1)
- component3 (params=1)
- copy (params=4)
- equals (params=2)
Daftar property member:
- judul: kotlin.String
- penulis: kotlin.String
- tahun: kotlin.Int
Java class: com.example.refleksi.Buku
Java isRecord: false
KFunction: sapa, param count=1
fnSapa.call("Budi") = Halo, Budi!
judulProp.getter.call(buku) = Kotlin Dasar
ringkasFn.call(buku) = Kotlin Dasar oleh Siti (2025)Mari kita bedah baris-baris kunci di atas:
- Baris 13 (
data class Buku): class yang akan diinspeksi. Karenadata class, hasil reflection akan menunjukkanisData = true. - Baris 21-22 (
fun infoBuku(kelas: KClass<Buku>)): menerimaKClassdan mencetak properti penting —simpleName(nama tanpa package),qualifiedName(nama lengkap),isData,isSealed, jumlah constructors, dan jumlah members. - Baris 31 (
kelas.memberFunctions.take(5)):memberFunctionsmengembalikan semua function member termasuk yang diwarisi dariAnysepertiequals,hashCode,toString. Untuk data class, juga termasukcopy,component1,component2, dst. - Baris 39 (
kelas.memberProperties): mengembalikan semua property member. UntukBuku, hasilnya adalahjudul,penulis, dantahun. - Baris 49-50 (
kelasLiteralvskelasInstance): dua cara mendapatKClass. Literal lebih tepat tipe-nya (KClass<Buku>), instance menghasilkan subtypeKClass<out Buku>. - Baris 56 (
kelasLiteral.java): properti.javamemberikanClass<Buku>dari Java reflection. Interop dua arah ini memungkinkan kita menggabungkan kekuatan Kotlin reflection (informasi data class, sealed) dan Java reflection (akses field, method private). - Baris 60 (
val fnSapa: KFunction<String> = ::sapa): reference ke function top-level.KFunction<String>adalah tipe dengan informasi tipe kembalianString. - Baris 65 (
val judulProp: KProperty<String> = Buku::judul): reference ke propertyBuku.judul.KProperty<String>adalah tipe property read-only dengan tipeString. - Baris 69 (
Buku::ringkas): reference ke member function. Berbeda dari top-level function, member function reference adalah unbound — pemanggilancall(buku)wajib menyertakan instance sebagai argumen pertama.
Interop dengan Java Reflection #
Properti KClass.java memberikan Class<T> Java. Sebaliknya, properti Class.kotlin memberikan KClass<T>. Kedua arah ini memungkinkan kita berpindah antara dua API sesuai kebutuhan.
Ketergantungan Library #
Pada target JVM, library kotlin-reflect wajib ditambahkan ke dependensi proyek bila memakai fitur lanjutan seperti memberProperties, primaryConstructor, atau hasAnnotation. Tanpa library ini, beberapa properti extension tidak tersedia dan kompilator menampilkan pesan “Please ensure that kotlin-reflect is in your classpath”.
Referensi Lanjutan #
- Reflection
— panduan resmi reflection Kotlin dan class reference
::class - kotlin.reflect package
— API reference paket
kotlin.reflectuntuk introspeksi runtime
Selanjutnya #
Setelah memahami dasar reflection, kita akan mendalami inspeksi class secara mendalam — termasuk membaca constructors, membuat instance via reflection, dan iterasi subtype sealed — topik chapter Inspecting Classes.