Reflection (refleksi) — mekanisme runtime yang memungkinkan kode untuk meneliti struktur dirinya sendiri: mendapatkan kelas, metode, bidang, dan anotasi tanpa mengetahui tipe pada tahap kompilasi. Alat ini menjadi dasar banyak framework seluler — serialisasi JSON (Gson, Moshi), dependency injection (Dagger, Koin), dan pelari tes (JUnit, XCTest). Menurut Oracle Java Reflection Tutorial, 2024, reflection adalah elemen wajib platform Java yang digunakan oleh semua pustaka besar.
Poin utama
Reflection — kemampuan program untuk mengamati dan memodifikasi struktur serta perilaku dirinya sendiri selama eksekusi. Dalam bahasa berorientasi objek, ini berarti memperoleh objek Class, Method, Field, dan Constructor, yang merepresentasikan elemen program sebagai data yang tersedia untuk dibaca dan dipanggil.
Istilah „reflection” diperkenalkan di komunitas kecerdasan buatan pada tahun 1982 (Brian Cantwell Smith) dan diimplementasikan dalam bahasa Smalltalk. Dalam pengembangan seluler, reflection pertama kali muncul di Java ME dan Objective-C (1986, NextStep). Saat ini setiap platform seluler besar memiliki API reflection-nya sendiri: Java/Kotlin untuk Android, Objective-C Runtime untuk iOS, Swift Mirror API untuk Swift.
Mekanisme reflection didasarkan pada metadata yang disimpan kompiler dalam bytecode atau file biner. Android menyimpan informasi lengkap tentang kelas dalam file DEX, iOS — dalam segmen __objc_classlist di Mach-O. Runtime memuat metadata ini ke memori dan menyediakan API untuk menelusurinya.
Java Reflection API dibangun di sekitar kelas java.lang.Class. Objek apa pun di Java dapat diubah menjadi Class melalui .getClass() atau Class.forName(). Dari Class diekstrak semua metode, bidang, konstruktor, anotasi, dan superclass. Kotlin mewarisi reflection Java dan menambahkan KClass, KFunction, KProperty sendiri dari paket kotlin.reflect.
import kotlin.reflect.full.declaredMemberFunctions
data class User(
val name: String,
val email: String
)
fun inspectClass() {
val kClass = User::class
val properties = kClass.declaredMemberProperties
val functions = kClass.declaredMemberFunctions
properties.forEach { prop ->
println("Properti: ${prop.name}, tipe: ${prop.returnType}")
}
}
Dalam contoh ini, KClass menyediakan metadata data class User. declaredMemberProperties mengembalikan daftar properti beserta tipe dan getter-nya. Reflection Kotlin terintegrasi erat dengan coroutine: KFunction mendukung modifier suspend, yang memungkinkan pemanggilan metode asinkron melalui reflection.
Reflection Java bekerja dengan Class<?>, Method.setAccessible(), dan Field.get(). setAccessible(true) menonaktifkan pemeriksaan akses Java language access control untuk elemen private. Ini adalah mekanisme yang kuat tetapi berbahaya: di Android, mulai dari API 28, pemanggilan setAccessible pada metode sistem yang tersembunyi dapat menyebabkan InaccessibleObjectException.
// Reflection Java: memanggil metode privat
Class> clazz = Class.forName("com.example.MyClass");
Object instance = clazz.getDeclaredConstructor().newInstance();
Method method = clazz.getDeclaredMethod("privateMethod", String.class);
method.setAccessible(true);
method.invoke(instance, "reflection test");
Kode tersebut mendemonstrasikan Class.forName() — pemuatan dinamis kelas berdasarkan nama string. Ini adalah dasar arsitektur plugin: kelas mungkin tidak diketahui pada tahap kompilasi, tetapi dimuat dan dieksekusi melalui reflection di runtime. getDeclaredMethod(„privateMethod”, ...) menemukan metode berdasarkan nama dan tipe parameter, dan invoke mengeksekusinya.
Objective-C runtime menyediakan fungsi class_copyMethodList, class_copyPropertyList, objc_getAssociatedObject. Tidak seperti Java, Objective-C tidak menyembunyikan metode privat secara default — runtime melihat semua metode kelas. Ini menjelaskan mengapa method swizzling bekerja tanpa setAccessible: runtime tidak memiliki enkapsulasi pada tingkat metadata.
Reflection digunakan di pustaka-pustaka kunci pengembangan seluler. Serialisasi JSON (Gson, Moshi, Kotlinx.serialization) memperoleh properti objek melalui reflection dan mencocokkannya dengan kunci JSON. Dependency injection (Dagger, Koin, Swinject) menganalisis konstruktor dan bidang untuk injeksi dependensi otomatis. Pustaka ORM (Room, Realm) menggunakan reflection untuk memetakan kelas ke tabel database.
Setiap penerapan ini bekerja tepat di runtime — kode tidak tahu sebelumnya kelas mana yang akan dihadapinya. Reflection menyediakan mekanisme universal untuk mengatasi ketidakpastian ini dengan mengorbankan performa dan keamanan.
Reflection 10–100 kali lebih lambat daripada pemanggilan metode langsung. Penyebabnya — tidak adanya optimasi JIT (devirtualization, inlining), pemeriksaan tipe pada setiap pemanggilan, dan pembungkusan parameter ke dalam Object[]/varargs. ART di Android 14 tidak dapat mengoptimalkan pemanggilan reflection secara inline karena metode target tidak diketahui hingga saat eksekusi.
| Operasi | Pemanggilan langsung | Melalui Reflection | Perlambatan |
|---|---|---|---|
| Memanggil metode tanpa parameter | ~3 ns | ~120 ns | 40x |
| Membaca bidang int | ~1 ns | ~85 ns | 85x |
| Memanggil metode dengan 2 parameter | ~4 ns | ~250 ns | 62x |
| Membuat instance melalui konstruktor | ~5 ns | ~180 ns | 36x |
| Menentukan kelas berdasarkan string | — | ~800 ns | — |
Data diperoleh pada Google Pixel 8 (Android 14, ART). Performa reflection meningkat dengan setiap versi Android: di Android 9, pemanggilan melalui Method.invoke() 150 kali lebih lambat daripada langsung, di Android 14 — 40 kali. ART menggunakan mekanisme method handle bawaan untuk optimasi.
Untuk bagian yang kritis terhadap performa, pengembang mengganti reflection dengan code generation: Dagger menggunakan annotation processing alih-alih pencarian runtime, Kotlinx.serialization menghasilkan serializer melalui KSP, Moshi mengadaptasi @JsonClass(generateAdapter = true) untuk codegen pada tahap kompilasi.
Annotation processing (KAPT, KSP) dan code generation — alternatif utama reflection dalam pengembangan seluler. Keduanya memindahkan analisis metadata dari runtime ke compile time: kode dihasilkan sebelum aplikasi dijalankan, yang menghilangkan overhead reflection dan meningkatkan performa.
// KSP: code generation alih-alih reflection
@Serializable
data class Config(
val apiUrl: String,
val timeout: Int
)
// KSP menghasilkan ConfigSerializer tanpa reflection
fun loadConfig(json: String): Config {
return Config.serializer().decodeFromString(json)
}
Dalam contoh ini, @Serializable adalah anotasi Kotlinx.serialization. KSP (Kotlin Symbol Processing) menganalisis kode sumber pada tahap kompilasi, menemukan semua kelas @Serializable, dan menghasilkan serializer. Selama eksekusi aplikasi, reflection tidak digunakan — serializer sudah dikompilasi menjadi kode mesin.
Code generation memberikan performa lebih baik, keamanan tipe, dan ukuran file biner yang lebih kecil (dead code elimination menghapus dependensi reflection yang tidak digunakan). Reflection tetap diperlukan untuk tugas-tugas di mana tipe tidak diketahui pada tahap kompilasi: pemuatan dinamis plugin, proxy runtime, instrumentasi pengujian. Menurut Kotlin, Kotlinx.serialization dengan KSP 3–5 kali lebih cepat daripada Gson yang berbasis reflection.
Reflection di platform seluler memiliki keterbatasan keamanan dan performa. Android mulai dari API 28 (Pie) membatasi setAccessible untuk antarmuka non-SDK — upaya membuka metode sistem tersembunyi menyebabkan pengecualian atau peringatan. iOS dengan Swift tidak mendukung reflection dalam pengertian klasik: Swift Mirror API hanya menyediakan pembacaan properti (name, value) tanpa modifikasi atau pemanggilan metode.
Google Play menolak aplikasi yang menggunakan reflection untuk menghindari batasan platform: mengganti layanan sistem, memodifikasi kebijakan SELinux, membaca izin yang dilindungi. Apple juga memblokir aplikasi yang memanggil API privat melalui reflection — pemeriksaan App Review memindai file biner untuk tanda tangan string objc_msgSend dengan selector privat yang dikenal.
ProGuard/R8 — keterbatasan lainnya. Obfuskasi dan minifikasi kode mengganti nama kelas dan metode menjadi nama pendek (a, b, c). Jika kode menggunakan Class.forName(„com.example.MyClass”), maka akan rusak setelah obfuskasi. Solusinya — aturan keep di proguard-rules.pro:
// Aturan keep ProGuard untuk reflection
-keep class com.example.** { *; }
-keep class * implements java.io.Serializable { *; }
-keepclassmembers class * {
@com.google.gson.annotations.SerializedName ;
}
-keepattributes Signature, InnerClasses, EnclosingMethod
Aturan -keep memberi tahu R8 untuk tidak mengganti nama kelas yang digunakan melalui reflection. Tanpa aturan ini, aplikasi yang terobfuskasi akan crash dengan ClassNotFoundException — runtime tidak dapat menemukan kelas berdasarkan nama string yang telah berubah.
Pertanyaan yang sering diajukan
Ya, reflection 10–100 kali lebih lambat daripada pemanggilan langsung. Penyebab utama: tidak adanya optimasi JIT (inlining, devirtualization), pembungkusan parameter, dan pemeriksaan tipe pada setiap pemanggilan. Untuk kode produksi, disarankan mengganti reflection dengan code generation melalui KSP atau annotation processing.
Reflection Java bekerja melalui Class, Method, Field dan memerlukan setAccessible untuk anggota private. Reflection Kotlin menggunakan KClass, KFunction, KProperty dan mendukung sealed class, data class, coroutine (fungsi suspend), dan null-safety. Reflection Kotlin berbasis reflection Java, tetapi menambahkan API type-safe.
Tambahkan aturan keep ProGuard/R8 untuk kelas, metode, dan bidang yang digunakan melalui reflection. Untuk setiap Class.forName(), getDeclaredMethod(), getDeclaredField() harus ada direktif -keep yang sesuai. Alat seperti GreenDAO dan Room secara otomatis menghasilkan aturan keep.
Swift tidak memiliki reflection dalam arti penuh. Mirror API (Swift 2+) memungkinkan membaca properti struktur atau kelas: nama, nilai, tipe. Pemanggilan metode, modifikasi bidang, dan pembuatan instance berdasarkan tipe tidak dimungkinkan. Untuk itu digunakan Objective-C Runtime saat mewarisi dari NSObject dengan @objc dynamic.
Gson (serialisasi JSON), Retrofit (pembuatan implementasi antarmuka melalui dynamic proxy), Mockito (pembuatan mock), Koin (dependency injection), Room (pemeriksaan Entity pada tahap kompilasi melalui KAPT), Firebase Crashlytics (analisis stack trace). Sebagian besar pustaka beralih ke code generation dengan KSP/KAPT.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga