Access/Modify Fields with Reflection
توضیحات جلسه
جزوه و مستندات
مفاهیم کلیدی
- Reflection
مکانیزمی در جاوا که به برنامهنویس اجازه میدهد در زمان اجرا (Runtime) به ساختار داخلی کلاسها، متدها و فیلدها دسترسی داشته باشد، آنها را بررسی کند (Inspect) و حتی مقادیر آنها را تغییر دهد (Modify).
- Field
شیئی در پکیج Reflection که نماینده یک متغیر (Variable) در کلاس است. از طریق این شیء میتوان به متادیتاها، نوع داده و مقدار متغیر دسترسی پیدا کرد.
- getField
متدی که فقط برای دسترسی به فیلدهای public یک کلاس استفاده میشود. اگر فیلد مورد نظر private باشد، این متد آن را پیدا نمیکند.
- getDeclaredField
متدی که به شما اجازه میدهد به تمامی فیلدهای تعریف شده در یک کلاس، از جمله فیلدهای private و protected دسترسی داشته باشید.
- setAccessible
متدی که برای دور زدن محدودیتهای دسترسی جاوا به کار میرود. با مقداردهی true به این متد، میتوان به فیلدهای private دسترسی پیدا کرد یا مقدار فیلدهای final را تغییر داد.
- Static Field
فیلدی که متعلق به خود کلاس است و نه یک Instance خاص. در Reflection برای کار با این فیلدها، نیازی به پاس دادن یک شیء مشخص نیست و میتوان از مقدار null استفاده کرد.
موارد مصاحبه ای
- چگونه میتوان به یک فیلد private که هیچ متد Getter یا Setter ندارد دسترسی پیدا کرد؟
با استفاده از متد getDeclaredField برای دریافت فیلد و سپس فراخوانی setAccessible(true) روی آن شیء فیلد، میتوان سد امنیتی جاوا را شکست و به مقدار آن دسترسی پیدا کرد یا آن را تغییر داد.
- تفاوت اصلی getField و getDeclaredField در چیست؟
متد getField فقط فیلدهای public را برمیگرداند (شامل فیلدهای ارثبری شده)، در حالی که getDeclaredField تمامی فیلدهایی که مستقیماً در خود کلاس تعریف شدهاند (اعم از private، public و غیره) را شامل میشود اما فیلدهای ارثبری شده را نمایش نمیدهد.
- آیا رفلکشن میتواند مقدار یک فیلد final را تغییر دهد؟
بله، با استفاده از رفلکشن و متد setAccessible(true) میتوان حتی مقدار فیلدهایی که final تعریف شدهاند را پس از مقداردهی اولیه تغییر داد. البته این کار به دلیل شکستن اصول طراحی کلاس، باید با احتیاط فراوان انجام شود.
- هنگام خواندن یا نوشتن مقدار یک فیلد static در رفلکشن، چه آبجکتی باید به متد get یا set پاس داده شود؟
از آنجایی که فیلدهای static متعلق به کلاس هستند و به هیچ شیء یا Instance خاصی وابستگی ندارند، میتوان به جای نام شیء، مقدار null را به این متدها پاس داد.
سناریو کاربردی
در این آموزش، سناریوی کار با کلاسی به نام A بررسی شده است که دارای فیلدهایی با سطوح دسترسی مختلف (مانند firstName به صورت private و age به صورت public) است.
۱. دسترسی و خواندن: ابتدا با استفاده از a.getClass() به شیء Class دسترسی پیدا میکنیم. برای فیلدهای عمومی از getField و برای فیلدهای خصوصی از getDeclaredField استفاده میشود. اگر فیلد خصوصی باشد، حتماً باید setAccessible(true) فراخوانی شود، در غیر این صورت با خطای IllegalAccessException مواجه میشویم.
۲. تغییر مقدار (Modify): با استفاده از متد set روی شیء فیلد، مقدار جدید را جایگزین میکنیم. برای مثال، مقدار فیلد firstName که private و final بود و مقدار "Farzad" داشت، بدون وجود هیچ متد Setter و تنها با قدرت رفلکشن به "Ali" تغییر داده شد. این مثال نشان میدهد که رفلکشن چگونه میتواند کپسولهسازی (Encapsulation) را در جاوا نادیده بگیرد.
بیشتر بدانید
- Handle Exceptions
کار با رفلکشن همیشه نیازمند مدیریت Exceptionهای چک شده (Checked Exceptions) مانند NoSuchFieldException و IllegalAccessException است. همیشه کد خود را در بلوکهای try-catch مناسب قرار دهید.
- Security Risks
استفاده از رفلکشن برای تغییر فیلدهای private و final مانند یک شمشیر دو لبه است؛ این قابلیت بسیار قدرتمند است اما میتواند امنیت و پایداری کد را به خطر بیندازد.
- Static Final Fields
تغییر دادن فیلدهایی که همزمان static و final هستند، بسیار دشوارتر است و معمولاً نیاز به روشهای خاصی دارد که در شرایط عادی توصیه نمیشود.
