Reflection (রিফ্লেকশন) একটি রানটাইম প্রক্রিয়া যা কোডকে নিজস্ব গঠন পরীক্ষা করার অনুমতি দেয়: কম্পাইল টাইমে টাইপ না জেনেই ক্লাস, মেথড, ফিল্ড এবং অ্যানোটেশন পাওয়া যায়। এই টুলটি অনেক মোবাইল ফ্রেমওয়ার্কের ভিত্তি — JSON সিরিয়ালাইজেশন (Gson, Moshi), ডিপেন্ডেন্সি ইনজেকশন (Dagger, Koin) এবং টেস্ট রানার (JUnit, XCTest)। Oracle Java Reflection Tutorial, 2024 অনুযায়ী, reflection Java প্ল্যাটফর্মের একটি বাধ্যতামূলক উপাদান, যা সব প্রধান লাইব্রেরি ব্যবহার করে।
মূল বিষয়
Reflection হলো এক্সিকিউশনের সময় নিজস্ব গঠন এবং আচরণ পর্যবেক্ষণ ও পরিবর্তন করার প্রোগ্রামের ক্ষমতা। অবজেক্ট-ওরিয়েন্টেড ভাষায় এর অর্থ হলো Class, Method, Field এবং Constructor অবজেক্ট পাওয়া, যা প্রোগ্রামের উপাদানগুলোকে পড়া ও কল করার জন্য উপলব্ধ ডেটা হিসেবে উপস্থাপন করে।
“reflection” শব্দটি 1982 সালে কৃত্রিম বুদ্ধিমত্তা সম্প্রদায়ে (Brian Cantwell Smith) প্রবর্তিত হয় এবং Smalltalk ভাষায় বাস্তবায়িত হয়। মোবাইল ডেভেলপমেন্টে reflection প্রথমবার Java ME এবং Objective-C (1986, NextStep)-এ আবির্ভূত হয়। আজ প্রতিটি প্রধান মোবাইল প্ল্যাটফর্মের নিজস্ব reflection API রয়েছে: Android-এর জন্য Java/Kotlin, iOS-এর জন্য Objective-C Runtime, Swift-এর জন্য Swift Mirror API।
Reflection প্রক্রিয়া মেটাডেটার উপর ভিত্তি করে, যা কম্পাইলার বাইটকোড বা বাইনারিতে সংরক্ষণ করে। Android DEX ফাইলে ক্লাস সম্পর্কে সম্পূর্ণ তথ্য সংরক্ষণ করে, iOS তা Mach-O সেগমেন্টের __objc_classlist বিভাগে সংরক্ষণ করে। রানটাইম এই মেটাডেটা মেমরিতে লোড করে এবং সেগুলো অতিক্রম করার জন্য API প্রদান করে।
Java Reflection API java.lang.Class ক্লাসকে ঘিরে গঠিত। Java-তে যেকোনো অবজেক্টকে .getClass() বা Class.forName() এর মাধ্যমে Class-এ রূপান্তর করা যায়। Class থেকে সমস্ত মেথড, ফিল্ড, কনস্ট্রাক্টর, অ্যানোটেশন এবং সুপারক্লাস নিষ্কাশিত হয়। Kotlin Java reflection উত্তরাধিকার সূত্রে পায় এবং kotlin.reflect প্যাকেজ থেকে নিজস্ব KClass, KFunction, KProperty যোগ করে।
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("বৈশিষ্ট্য: ${prop.name}, টাইপ: ${prop.returnType}")
}
}
এই উদাহরণে KClass data class User-এর জন্য মেটাডেটা প্রদান করে। declaredMemberProperties তাদের টাইপ এবং গেটারসহ বৈশিষ্ট্যের তালিকা ফেরত দেয়। Kotlin reflection coroutines-এর সাথে ঘনিষ্ঠভাবে একীভূত: KFunction suspend মডিফায়ার সমর্থন করে, যা reflection-এর মাধ্যমে অ্যাসিঙ্ক্রোনাস মেথড কল করার অনুমতি দেয়।
Java reflection Class<?>, Method.setAccessible() এবং Field.get() এর সাথে কাজ করে। setAccessible(true) প্রাইভেট উপাদানের জন্য Java ভাষা অ্যাক্সেস কন্ট্রোল পরীক্ষা নিষ্ক্রিয় করে। এটি শক্তিশালী কিন্তু বিপজ্জনক প্রক্রিয়া: Android-এ API 28 থেকে শুরু করে, লুকানো সিস্টেম মেথডে setAccessible কল করলে InaccessibleObjectException হতে পারে।
// Java reflection: একটি প্রাইভেট মেথডের কল
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");
কোডটি Class.forName() প্রদর্শন করে — স্ট্রিং নামের মাধ্যমে গতিশীল ক্লাস লোডিং। এটি প্লাগইন আর্কিটেকচারের ভিত্তি: একটি ক্লাস কম্পাইল টাইমে অজানা থাকতে পারে, তবে রানটাইমে reflection-এর মাধ্যমে লোড ও এক্সিকিউট করা যায়। getDeclaredMethod(“privateMethod”, ...) নাম এবং প্যারামিটার টাইপ অনুযায়ী একটি মেথড খুঁজে পায়, এবং invoke তা সম্পাদন করে।
Objective-C runtime class_copyMethodList, class_copyPropertyList, objc_getAssociatedObject ফাংশন প্রদান করে। Java-র বিপরীতে, Objective-C ডিফল্টরূপে প্রাইভেট মেথড লুকায় না — রানটাইম ক্লাসের সব মেথড দেখে। এটিই ব্যাখ্যা করে কেন method swizzling setAccessible ছাড়াই কাজ করে: রানটাইমে মেটাডেটা স্তরে এনক্যাপসুলেশন নেই।
Reflection মোবাইল ডেভেলপমেন্টের প্রধান লাইব্রেরিগুলোতে ব্যবহৃত হয়। JSON সিরিয়ালাইজেশন (Gson, Moshi, Kotlinx.serialization) reflection-এর মাধ্যমে অবজেক্টের বৈশিষ্ট্য পায় এবং সেগুলোকে JSON কী-এর সাথে মিলিয়ে দেয়। ডিপেন্ডেন্সি ইনজেকশন (Dagger, Koin, Swinject) স্বয়ংক্রিয় ডিপেন্ডেন্সি ইনজেকশনের জন্য কনস্ট্রাক্টর এবং ফিল্ড বিশ্লেষণ করে। ORM লাইব্রেরি (Room, Realm) ডেটাবেস টেবিলে ক্লাস ম্যাপ করার জন্য reflection ব্যবহার করে।
এই প্রতিটি প্রয়োগ ঠিক রানটাইমে কাজ করে — কোড আগে থেকেই জানে না কোন ক্লাসের সম্মুখীন হবে। Reflection কর্মক্ষমতা এবং নিরাপত্তার মূল্যে এই অনিশ্চয়তা দূর করার জন্য একটি সার্বজনীন প্রক্রিয়া প্রদান করে।
Reflection সরাসরি মেথড কলের চেয়ে 10–100 গুণ ধীর। কারণ JIT অপটিমাইজেশনের অভাব (devirtualization, inlining), প্রতিটি কলের সময় টাইপ পরীক্ষা এবং প্যারামিটারগুলোকে Object[]/varargs-এ প্যাক করা। Android 14-এর ART reflection কলকে inline-অপটিমাইজ করতে পারে না কারণ লক্ষ্য মেথড এক্সিকিউশনের মুহূর্ত পর্যন্ত অজানা থাকে।
| অপারেশন | সরাসরি কল | Reflection-এর মাধ্যমে | ধীরগতি |
|---|---|---|---|
| প্যারামিটারবিহীন মেথড কল | ~3 ns | ~120 ns | 40x |
| int ফিল্ড পড়া | ~1 ns | ~85 ns | 85x |
| 2 প্যারামিটারসহ মেথড কল | ~4 ns | ~250 ns | 62x |
| কনস্ট্রাক্টরের মাধ্যমে ইনস্ট্যান্স তৈরি | ~5 ns | ~180 ns | 36x |
| স্ট্রিং দিয়ে ক্লাস নির্ধারণ | — | ~800 ns | — |
ডেটা Google Pixel 8 (Android 14, ART) এ প্রাপ্ত। প্রতিটি Android সংস্করণের সাথে reflection-এর কর্মক্ষমতা উন্নত হয়: Android 9-এ Method.invoke() এর মাধ্যমে কল সরাসরি কলের চেয়ে 150 গুণ ধীর ছিল, Android 14-এ 40 গুণ। ART অপটিমাইজেশনের জন্য অন্তর্নির্মিত method handle প্রক্রিয়া ব্যবহার করে।
কর্মক্ষমতা-সংবেদনশীল অংশগুলোর জন্য ডেভেলপাররা reflection-কে কোড জেনারেশন দিয়ে প্রতিস্থাপন করে: Dagger রানটাইম অনুসন্ধানের পরিবর্তে অ্যানোটেশন প্রসেসিং ব্যবহার করে, Kotlinx.serialization KSP-র মাধ্যমে সিরিয়ালাইজার তৈরি করে, Moshi কম্পাইল-টাইম codegen-এর জন্য @JsonClass(generateAdapter = true) প্রয়োগ করে।
অ্যানোটেশন প্রসেসিং (KAPT, KSP) এবং কোড জেনারেশন মোবাইল ডেভেলপমেন্টে reflection-এর প্রধান বিকল্প। তারা মেটাডেটা বিশ্লেষণকে রানটাইম থেকে কম্পাইল টাইমে স্থানান্তরিত করে: কোড অ্যাপ চালু হওয়ার আগে তৈরি হয়, যা reflection ওভারহেড দূর করে এবং কর্মক্ষমতা উন্নত করে।
// KSP: reflection-এর পরিবর্তে কোড জেনারেশন
@Serializable
data class Config(
val apiUrl: String,
val timeout: Int
)
// KSP reflection ছাড়াই ConfigSerializer তৈরি করে
fun loadConfig(json: String): Config {
return Config.serializer().decodeFromString(json)
}
এই উদাহরণে @Serializable হলো Kotlinx.serialization-এর অ্যানোটেশন। KSP (Kotlin Symbol Processing) কম্পাইল টাইমে সোর্স কোড বিশ্লেষণ করে, সমস্ত @Serializable ক্লাস খুঁজে পায় এবং সিরিয়ালাইজার তৈরি করে। অ্যাপ্লিকেশন এক্সিকিউশনের সময় reflection ব্যবহৃত হয় না — সিরিয়ালাইজারটি ইতোমধ্যে মেশিন কোডে কম্পাইল করা।
কোড জেনারেশন ভালো কর্মক্ষমতা, টাইপ নিরাপত্তা এবং ছোট বাইনারি আকার প্রদান করে (ডেড কোড এলিমিনেশন অব্যবহৃত reflection নির্ভরতা সরিয়ে দেয়)। Reflection সেসব কাজের জন্য প্রয়োজনীয় থাকে যেখানে টাইপ কম্পাইল টাইমে অজানা: গতিশীল প্লাগইন লোডিং, রানটাইম প্রক্সি, টেস্ট ইনস্ট্রুমেন্টেশন। Kotlin অনুযায়ী, KSP-সহ Kotlinx.serialization reflection-ভিত্তিক Gson-এর চেয়ে 3–5 গুণ দ্রুত।
মোবাইল প্ল্যাটফর্মে Reflection-এর নিরাপত্তা ও কর্মক্ষমতা সীমাবদ্ধতা রয়েছে। Android API 28 (Pie) থেকে শুরু করে non-SDK ইন্টারফেসের জন্য setAccessible সীমাবদ্ধ করে — লুকানো সিস্টেম মেথড খোলার চেষ্টা ব্যতিক্রম বা সতর্কতা সৃষ্টি করে। Swift সহ iOS ক্লাসিক অর্থে reflection সমর্থন করে না: Swift Mirror API শুধুমাত্র বৈশিষ্ট্য পড়ার সুযোগ দেয় (নাম, মান), পরিবর্তন বা মেথড কল ছাড়াই।
Google Play সেই অ্যাপ্লিকেশন প্রত্যাখ্যান করে যেগুলো প্ল্যাটফর্ম সীমাবদ্ধতা অতিক্রম করতে reflection ব্যবহার করে: সিস্টেম সার্ভিস প্রতিস্থাপন, SELinux নীতি পরিবর্তন, সুরক্ষিত অনুমতি পড়া। Appleও reflection-এর মাধ্যমে প্রাইভেট API কলকারী অ্যাপ্লিকেশন ব্লক করে — App Review পরীক্ষা পরিচিত প্রাইভেট সিলেক্টরসহ objc_msgSend-এর স্ট্রিং স্বাক্ষরের জন্য বাইনারি স্ক্যান করে।
ProGuard/R8 আরেকটি সীমাবদ্ধতা। অবফাসকেশন এবং কোড মিনিফিকেশন ক্লাস ও মেথডকে ছোট নামে (a, b, c) পুনঃনামকরণ করে। কোড যদি Class.forName(“com.example.MyClass”) ব্যবহার করে, অবফাসকেশনের পরে তা ভেঙে যাবে। সমাধান হলো proguard-rules.pro ফাইলে keep rules:
// reflection-এর জন্য ProGuard keep নিয়ম
-keep class com.example.** { *; }
-keep class * implements java.io.Serializable { *; }
-keepclassmembers class * {
@com.google.gson.annotations.SerializedName ;
}
-keepattributes Signature, InnerClasses, EnclosingMethod
-keep নিয়মগুলো R8-কে বলে reflection-এর মাধ্যমে ব্যবহৃত ক্লাস পুনঃনামকরণ না করতে। এই নিয়ম ছাড়া, অবফাসকেটেড অ্যাপ ClassNotFoundException দিয়ে ক্র্যাশ করবে — রানটাইম পরিবর্তিত স্ট্রিং নাম দিয়ে ক্লাসটি খুঁজে পাবে না।
সচরাচর জিজ্ঞাসিত প্রশ্ন
হ্যাঁ, reflection সরাসরি কলের চেয়ে 10–100 গুণ ধীর। প্রধান কারণ: JIT অপটিমাইজেশনের অভাব (inlining, devirtualization), প্যারামিটার প্যাকিং এবং প্রতিটি কলের সময় টাইপ পরীক্ষা। প্রোডাকশন কোডের জন্য KSP বা অ্যানোটেশন প্রসেসিংয়ের মাধ্যমে reflection-কে কোড জেনারেশন দিয়ে প্রতিস্থাপন করার পরামর্শ দেওয়া হয়।
Java reflection Class, Method, Field এর মাধ্যমে কাজ করে এবং প্রাইভেট সদস্যদের জন্য setAccessible প্রয়োজন। Kotlin reflection KClass, KFunction, KProperty ব্যবহার করে এবং sealed class, data class, coroutines (suspend ফাংশন) এবং null-safety সমর্থন করে। Kotlin reflection Java reflection-এর উপর ভিত্তি করে তবে type-safe API যোগ করে।
reflection-এর মাধ্যমে ব্যবহৃত ক্লাস, মেথড এবং ফিল্ডের জন্য ProGuard/R8 keep rules যোগ করুন। প্রতিটি Class.forName(), getDeclaredMethod(), getDeclaredField() এর জন্য সংশ্লিষ্ট -keep নির্দেশনা থাকতে হবে। GreenDAO এবং Room-এর মতো টুল স্বয়ংক্রিয়ভাবে keep rules তৈরি করে।
Swift-এ সম্পূর্ণ অর্থে reflection নেই। Mirror API (Swift 2+) স্ট্রাকচার বা ক্লাসের বৈশিষ্ট্য পড়ার সুযোগ দেয়: নাম, মান, টাইপ। মেথড কল, ফিল্ড পরিবর্তন এবং টাইপ দিয়ে ইনস্ট্যান্স তৈরি করা অসম্ভব। এর জন্য NSObject থেকে @objc dynamic সহ উত্তরাধিকারসূত্রে পেলে Objective-C Runtime ব্যবহৃত হয়।
Gson (JSON সিরিয়ালাইজেশন), Retrofit (dynamic proxy-র মাধ্যমে ইন্টারফেস ইমপ্লিমেন্টেশন তৈরি), Mockito (মক তৈরি), Koin (ডিপেন্ডেন্সি ইনজেকশন), Room (KAPT-র মাধ্যমে কম্পাইল টাইমে Entity পরীক্ষা), Firebase Crashlytics (স্ট্যাক ট্রেস বিশ্লেষণ)। অধিকাংশ লাইব্রেরি KSP/KAPT সহ কোড জেনারেশনের দিকে যাচ্ছে।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন