Tətbiq hazırlanmasında Reflection — nədir, refleksiya mexanizmləri və necə tətbiq edilir

Müəllif: IT Sectr Dərc olunub: 2026-05-17 Oxuma vaxtı: 8 dəq

Reflection (refleksiya) — runtime mexanizmi olub, koda öz strukturunu tədqiq etməyə imkan verir: kompilyasiya mərhələsində tipləri bilmədən sinifləri, metodları, sahələri və annotasiyaları əldə etməyə imkan verir. Bu alət bir çox mobil freymvorkların — JSON serializasiyasının (Gson, Moshi), dependency injection-un (Dagger, Koin) və test runner-larının (JUnit, XCTest) əsasını təşkil edir. Oracle Java Reflection Tutorial, 2024 məlumatına görə, reflection bütün böyük kitabxanalar tərəfindən istifadə olunan Java platformasının məcburi elementidir.

Əsas məqamlar

  • Reflection — proqramın icrası zamanı siniflərin, metodların və sahələrin metadata məlumatlarına giriş.
  • Java Reflection API dinamik analiz üçün Class, Method, Field və Constructor siniflərini təqdim edir.
  • Kotlin reflection korutinlər və serializasiya ilə inteqrasiya olunmuş KClass və KFunction-dan istifadə edir.
  • Objective-C Runtime — class_copyMethodList və objc_getClass vasitəsilə reflection forması.
  • Reflection-un performansı JIT-optimizasiyaların olmaması səbəbindən birbaşa çağırışlardan 10–100 dəfə aşağıdır.

Reflection nədir?

Reflection — proqramın icra zamanı öz strukturunu və davranışını müşahidə etmə və dəyişdirmə qabiliyyəti. Obyekt-yönümlü dillərdə bu, proqramın elementlərini oxunma və çağırış üçün əlçatan verilənlər kimi təqdim edən Class, Method, Field və Constructor obyektlərinin əldə edilməsi deməkdir.

„reflection” termini 1982-ci ildə süni intellekt icmasında (Brian Cantwell Smith) təqdim edilmiş və Smalltalk dilində reallaşdırılmışdır. Mobil inkişafda reflection ilk dəfə Java ME və Objective-C (1986, NextStep) dillərində meydana çıxmışdır. Bu gün hər böyük mobil platformanın öz reflection API-si var: Android üçün Java/Kotlin, iOS üçün Objective-C Runtime, Swift üçün Swift Mirror API.

Reflection mexanizmi kompilyatorun bayt-kodda və ya binar faylda saxladığı metadata məlumatlarına əsaslanır. Android siniflər haqqında tam məlumatı DEX-fayllarında saxlayır, iOS — Mach-O-nun __objc_classlist seqmentində. Runtime bu metadata məlumatlarını yaddaşa yükləyir və onların keçilməsi üçün API təqdim edir.

Java və Kotlin-də Reflection necə işləyir

Java Reflection API java.lang.Class sinifi ətrafında qurulur. Java-da istənilən obyekti .getClass() və ya Class.forName() vasitəsilə Class-a çevirmək olar. Class-dan bütün metodlar, sahələr, konstruktorlar, annotasiyalar və super-siniflər çıxarılır. Kotlin Java reflection-u miras alır və kotlin.reflect paketindən öz KClass, KFunction, KProperty-lərini əlavə edir.

kotlin
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("Xüsusiyyət: ${prop.name}, tip: ${prop.returnType}")
    }
}

Bu nümunədə KClass data class User-in metadata məlumatlarını təqdim edir. declaredMemberProperties tipləri və getter-ləri ilə birlikdə xassələrin siyahısını qaytarır. Kotlin reflection korutinlərlə sıx inteqrasiya olunub: KFunction suspend-mofifikatoru dəstəkləyir və bu, asinxron metodları reflection vasitəsilə çağırmağa imkan verir.

Java Reflection: Class, Method, Field

Java reflection Class<?>, Method.setAccessible() və Field.get() ilə işləyir. setAccessible(true) private-elementlər üçün Java language access control giriş yoxlamasını söndürür. Bu güclü, lakin təhlükəli mexanizmdir: Android-də API 28-dən başlayaraq gizli sistem metodlarında setAccessible çağırışı InaccessibleObjectException-a səbəb ola bilər.

java
// Java reflection: privat metodun çağırılması
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");

Kod Class.forName() metodunu nümayiş etdirir — sinfin sətir adı ilə dinamik yüklənməsi. Bu, plagin arxitekturalarının əsasıdır: sinif kompilyasiya mərhələsində məlum olmaya bilər, lakin runtime-da reflection vasitəsilə yüklənib icra olunur. getDeclaredMethod(„privateMethod”, ...) metodu ad və parametr tiplərinə görə tapır, invoke isə onu icra edir.

Objective-C Runtime: refleksiyanın alternativ modeli

Objective-C runtime class_copyMethodList, class_copyPropertyList, objc_getAssociatedObject funksiyalarını təqdim edir. Java-dan fərqli olaraq, Objective-C private metodları standart olaraq gizlətmir — runtime sinfin bütün metodlarını görür. Bu, method swizzling-in nə üçün setAccessible olmadan işlədiyini izah edir: runtime metadata səviyyəsində inkapsulyasiyaya malik deyil.

Mobil inkişafda Reflection-un tətbiqi

Reflection mobil inkişafın əsas kitabxanalarında istifadə olunur. JSON serializasiyası (Gson, Moshi, Kotlinx.serialization) obyektin xassələrini reflection vasitəsilə əldə edir və onları JSON açarları ilə uyğunlaşdırır. Dependency injection (Dagger, Koin, Swinject) asılılıqların avtomatik yerləşdirilməsi üçün konstruktorları və sahələri analiz edir. ORM kitabxanaları (Room, Realm) sinifləri verilənlər bazası cədvəllərinə uyğunlaşdırmaq üçün reflection-dan istifadə edir.

  • Serializasiya — Gson Field.get() vasitəsilə obyektin elan edilmiş sahələrini oxuyur və @SerializedName annotasiyalarına əsasən JSON yaradır.
  • Dependency Injection — Dagger annotation processing vasitəsilə kod generasiya edir, Koin runtime-həlli üçün Kotlin reflection-dan istifadə edir.
  • Testləşdirmə — JUnit @Test ilə metodları reflection vasitəsilə tapır və çağırır; Mockito dynamic proxy vasitəsilə mock-lar yaradır.
  • Verilənlər bazası — Room Entity sahələrini Class.getDeclaredFields() vasitəsilə kompilyasiya mərhələsində (KAPT/KSP ilə) yoxlayır.
  • Analitika və monitorinq — Firebase Crashlytics stack trace-i reflection-a əsaslanan Throwable.getStackTrace() vasitəsilə əldə edir.

Bu tətbiqlərin hər biri məhz runtime-da işləyir — kod əvvəlcədən hansı siniflərlə qarşılaşacağını bilmir. Reflection bu qeyri-müəyyənliyi performans və təhlükəsizlik bahasına keçmək üçün universal mexanizm təqdim edir.

Reflection-un performansı: dinamik girişin qiyməti

Reflection metodların birbaşa çağırılmasından 10–100 dəfə yavaşdır. Səbəb — JIT-optimizasiyaların (devirtualization, inlining) olmaması, hər çağırışda tiplərin yoxlanılması və parametrlərin Object[]/varargs-a yığılmasıdır. Android 14-də ART reflection-çağırışlarını inline-optimizasiya edə bilmir, çünki hədəf metod icra anına qədər məlum deyil.

ƏməliyyatBirbaşa çağırışReflection vasitəsiləYavaşlama
Parametrsiz metod çağırışı~3 ns~120 ns40x
int sahəsinin oxunması~1 ns~85 ns85x
2 parametrli metod çağırışı~4 ns~250 ns62x
Konstruktor vasitəsilə nüsxə yaradılması~5 ns~180 ns36x
Sinfin sətir üzrə müəyyən edilməsi~800 ns

Məlumatlar Google Pixel 8 cihazında (Android 14, ART) əldə edilib. Reflection-un performansı Android-in hər versiyası ilə yaxşılaşır: Android 9-da Method.invoke() vasitəsilə çağırış birbaşa çağırışdan 150 dəfə, Android 14-də isə 40 dəfə yavaş idi. ART optimizasiya üçün method handle daxili mexanizmlərindən istifadə edir.

Performans baxımından kritik hissələrdə tərtibatçılar reflection-u kod-generasiya ilə əvəz edirlər: Dagger runtime-axtarış əvəzinə annotation processing istifadə edir, Kotlinx.serialization KSP vasitəsilə serializatorlar generasiya edir, Moshi compile-time codegen üçün @JsonClass(generateAdapter = true) tətbiq edir.

Reflection-a alternativlər: annotasiyalar və code generation

Annotation processing (KAPT, KSP) və code generation — mobil inkişafda reflection-un əsas alternativləridir. Onlar metadata analizini runtime-dan compile time-a köçürür: kod tətbiqin işə salınmasından əvvəl generasiya olunur, bu da reflection overhead-i aradan qaldırır və performansı yaxşılaşdırır.

kotlin
// KSP: reflection əvəzinə code generation
@Serializable
data class Config(
    val apiUrl: String,
    val timeout: Int
)

// KSP ConfigSerializer-i reflection olmadan generasiya edir
fun loadConfig(json: String): Config {
    return Config.serializer().decodeFromString(json)
}

Bu nümunədə @Serializable — Kotlinx.serialization annotasiyasıdır. KSP (Kotlin Symbol Processing) kompilyasiya mərhələsində mənbə kodu analiz edir, bütün @Serializable siniflərini tapır və serializatorlar generasiya edir. Tətbiqin icrası zamanı reflection istifadə olunmur — serializator artıq maşın koduna kompilyasiya olunub.

Yanaşmaların müqayisəsi

Code generation daha yaxşı performans, tip təhlükəsizliyi və daha kiçik binar fayl ölçüsü təmin edir (dead code elimination istifadə olunmayan reflection asılılıqlarını silir). Reflection tiplərin kompilyasiya mərhələsində məlum olmadığı hallar üçün zəruri olaraq qalır: plaginlərin dinamik yüklənməsi, runtime-proksi, testlərin instrumentasiyası. Kotlin-in məlumatına görə, KSP ilə Kotlinx.serialization reflection-a əsaslanan Gson-dan 3–5 dəfə sürətlidir.

Android və iOS-da Reflection-un məhdudiyyətləri

Reflection mobil platformalarda təhlükəsizlik və performans məhdudiyyətlərinə malikdir. Android API 28-dən (Pie) başlayaraq non-SDK interfeyslər üçün setAccessible-ı məhdudlaşdırır — gizli sistem metodunu açmaq cəhdi istisnaya və ya xəbərdarlığa səbəb olur. iOS Swift ilə reflection-u klassik mənada dəstəkləmir: Swift Mirror API yalnız xassələrin oxunmasını (name, value) təmin edir, metodların dəyişdirilməsi və ya çağırılması olmadan.

Google Play platforma məhdudiyyətlərini keçmək üçün reflection-dan istifadə edən tətbiqləri rədd edir: sistem xidmətlərinin əvəzlənməsi, SELinux siyasətlərinin dəyişdirilməsi, qorunan icazələrin oxunması. Apple da reflection vasitəsilə private API çağıran tətbiqləri bloklayır — App Review yoxlaması binari faylı məlum private seçiciləri olan objc_msgSend sətir imzaları üçün skan edir.

ProGuard/R8 — daha bir məhdudiyyət. Kodun obfuskasiyası və minifikasiyası sinifləri və metodları qısa adlarla (a, b, c) adlandırır. Kod Class.forName(„com.example.MyClass”) istifadə edirsə, obfuskasiyadan sonra sınacaq. Həll — proguard-rules.pro faylında keep-qaydaları:

groovy
// Reflection üçün ProGuard keep-qaydaları
-keep class com.example.** { *; }
-keep class * implements java.io.Serializable { *; }
-keepclassmembers class * {
    @com.google.gson.annotations.SerializedName ;
}
-keepattributes Signature, InnerClasses, EnclosingMethod

-keep qaydaları R8-ə reflection vasitəsilə istifadə olunan sinifləri adlandırmamağı bildirir. Bu qaydalar olmadan obfuskasiya olunmuş tətbiq ClassNotFoundException ilə çökəcək — runtime sinfi dəyişmiş sətir adı ilə tapa bilməyəcək.

Tez-tez verilən suallar

Reflection tətbiqin performansı üçün zərərlidirmi?

Bəli, reflection birbaşa çağırışdan 10–100 dəfə yavaşdır. Əsas səbəblər: JIT-optimizasiyaların (inlining, devirtualization) olmaması, parametrlərin yığılması və hər çağırışda tiplərin yoxlanılması. Production-kod üçün reflection-u KSP və ya annotation processing vasitəsilə code generation ilə əvəz etmək tövsiyə olunur.

Java reflection Kotlin reflection-dan nə ilə fərqlənir?

Java reflection Class, Method, Field vasitəsilə işləyir və private üzvlər üçün setAccessible tələb edir. Kotlin reflection KClass, KFunction, KProperty istifadə edir və sealed class, data class, korutinlər (suspend-funksiyalar) və null-safety dəstəkləyir. Kotlin reflection Java reflection-na əsaslanır, lakin type-safe API əlavə edir.

Reflection-dan istifadə zamanı obfuskasiya problemlərindən necə qaçınmaq olar?

Reflection vasitəsilə istifadə olunan siniflər, metodlar və sahələr üçün ProGuard/R8 keep-qaydaları əlavə edin. Hər Class.forName(), getDeclaredMethod(), getDeclaredField() üçün müvafiq -keep direktivi olmalıdır. GreenDAO və Room kimi alətlər keep-qaydalarını avtomatik generasiya edir.

Swift-də Reflection varmı?

Swift-də reflection tam mənada yoxdur. Mirror API (Swift 2+) strukturun və ya sinfin xassələrini oxumağa imkan verir: ad, dəyər, tip. Metodların çağırılması, sahələrin dəyişdirilməsi və tip üzrə nüsxələrin yaradılması mümkün deyil. Bunun üçün @objc dynamic ilə NSObject-dən miras alarkən Objective-C Runtime istifadə olunur.

Hansı kitabxanalar Android-də Reflection istifadə edir?

Gson (JSON-serializasiya), Retrofit (dynamic proxy vasitəsilə interfeys implementation-larının yaradılması), Mockito (mock-ların yaradılması), Koin (dependency injection), Room (Entity yoxlanışı kompilyasiya mərhələsində KAPT ilə), Firebase Crashlytics (stack trace analizi). Əksər kitabxanalar KSP/KAPT ilə code generation-a keçir.

Nəticələr

  • Reflection — siniflərin, metodların və sahələrin metadata məlumatlarına giriş üçün runtime mexanizmi.
  • Java reflection Class, Method, Field istifadə edir; Kotlin — korutinlərlə inteqrasiya ilə KClass, KFunction, KProperty.
  • Objective-C Runtime giriş məhdudiyyəti olmadan class_copyMethodList və objc_getClass təqdim edir.
  • Reflection daha yavaşdır — JIT-optimizasiyaların olmaması səbəbindən birbaşa çağırışdan 10–100 dəfə.
  • Alternativlər — code generation (KSP, KAPT) və annotation processing — reflection overhead-i aradan qaldırır.
  • ProGuard/R8 Class.forName() və getDeclaredMethod() ilə istifadə olunan siniflər üçün keep-qaydaları tələb edir.
  • Reflection tiplərin kompilyasiya mərhələsində məlum olmadığı plaginlərin dinamik yüklənməsi, DI və test freymvorkları üçün əvəzsizdir.

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun