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 #

TipePadanan JavaKegunaan
KClass<T>Class<T>Mewakili class atau object Kotlin.
KFunction<R>Method / ConstructorMewakili function, method, atau constructor.
KProperty<V>Field + getter/setterMewakili 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:

kotlin Cara mendapat 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 #

kotlin
// 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:

text
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:

  1. Baris 13 (data class Buku): class yang akan diinspeksi. Karena data class, hasil reflection akan menunjukkan isData = true.
  2. Baris 21-22 (fun infoBuku(kelas: KClass<Buku>)): menerima KClass dan mencetak properti penting — simpleName (nama tanpa package), qualifiedName (nama lengkap), isData, isSealed, jumlah constructors, dan jumlah members.
  3. Baris 31 (kelas.memberFunctions.take(5)): memberFunctions mengembalikan semua function member termasuk yang diwarisi dari Any seperti equals, hashCode, toString. Untuk data class, juga termasuk copy, component1, component2, dst.
  4. Baris 39 (kelas.memberProperties): mengembalikan semua property member. Untuk Buku, hasilnya adalah judul, penulis, dan tahun.
  5. Baris 49-50 (kelasLiteral vs kelasInstance): dua cara mendapat KClass. Literal lebih tepat tipe-nya (KClass<Buku>), instance menghasilkan subtype KClass<out Buku>.
  6. Baris 56 (kelasLiteral.java): properti .java memberikan Class<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).
  7. Baris 60 (val fnSapa: KFunction<String> = ::sapa): reference ke function top-level. KFunction<String> adalah tipe dengan informasi tipe kembalian String.
  8. Baris 65 (val judulProp: KProperty<String> = Buku::judul): reference ke property Buku.judul. KProperty<String> adalah tipe property read-only dengan tipe String.
  9. Baris 69 (Buku::ringkas): reference ke member function. Berbeda dari top-level function, member function reference adalah unbound — pemanggilan call(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.reflect untuk 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.