Generic Type Erasure
📖توضیحات درس
📄جزوه
مفاهیم کلیدی
-
Type Erasure فرآیندی که در آن کامپایلر تمام اطلاعات مربوط به
Genericرا در زمانCompile Timeحذف میکند تا کد با نسخههای قدیمیتر جاوا سازگار باشد. در واقع، خروجی نهایی یا همانBytecodeفاقد هرگونه اطلاعات جنریک است. -
Raw Type به حالتی گفته میشود که یک کلاس یا اینترفیس جنریک بدون مشخص کردن تایپ پارامتر استفاده شود؛ مثلاً استفاده از
Listبه جایList<String>. کامپایلر در فرآیند پاکسازی نوع، پارامترها را با این حالت جایگزین میکند. -
Upper Bound محدودیتی که با کلمه کلیدی
extendsروی تایپ پارامتر اعمال میشود (مثلاً<T extends Number>). این کار باعث میشود کامپایلر بداند که تایپ ورودی حتماً باید از یک کلاس خاص مشتق شده باشد. -
Diamond Operator علامت
<>که در جاوا برای جلوگیری از تکرار تایپ در هنگام نمونهسازی استفاده میشود. کامپایلر در زمانCompile Timeمحتویات داخل این اپراتور را حذف میکند. -
Casting عملیاتی که کامپایلر پس از حذف اطلاعات جنریک انجام میدهد تا اطمینان حاصل کند مقادیر بازگشتی با نوع مورد انتظار برنامه همخوانی دارند و امنیت کد (Type Safety) حفظ میشود.
موارد مصاحبه ای
-
مفهوم Type Erasure چیست؟ پاکسازی نوع فرآیندی است که طی آن کامپایلر جاوا اطلاعات جنریک را حذف کرده و آنها را با تایپهای واقعی (مانند
Objectیا کرانهای بالا) جایگزین میکند تا در زمانRuntimeمشکلی برای اجرای کد وجود نداشته باشد. -
اگر یک تایپ پارامتر بدون محدودیت (Unbounded) باشد، با چه چیزی جایگزین میشود؟ در صورتی که پارامتر به صورت
<T>تعریف شده باشد، کامپایلر آن را با کلاسObjectجایگزین میکند. -
تایپ پارامتر در حالت Bounded (مثلاً
<T extends Number>) به چه چیزی تبدیل میشود؟ در این حالت، کامپایلر تمامی تکرارهایTرا با اولین کران بالا که در اینجاNumberاست، جایگزین میکند. -
در صورت وجود چندین محدودیت (Multiple Bonding) مانند
<T extends A & B>چه اتفاقی میافتد؟ کامپایلر تایپ پارامتر را با اولین کلاس یا اینترفیس ذکر شده در لیست محدودیتها (در اینجا کلاسA) جایگزین میکند. -
چرا در خروجی نهایی بایتکد، اثری از جنریک نیست؟ به این دلیل که جنریکها در جاوا در سطح کامپایلر مدیریت میشوند و برای حفظ سازگاری عقبرو (Backward Compatibility) با نسخههای قدیمی JVM، در لایه بایتکد حذف میشوند.
سناریو کاربردی
فرض کنید یک کلاس جنریک به نام Stack<E> دارید که درون آن آرایهای از جنس E تعریف شده است.
۱. قبل از کامپایل: شما کدی مینویسید که در آن Stack<String> ایجاد شده و فقط رشته دریافت میکند. این کار امنیت کد شما را در مرحله توسعه تضمین میکند.
۲. در مرحله Type Erasure: کامپایلر تمامی Eها را بررسی میکند. اگر E محدود نشده باشد، آن را به Object تبدیل میکند. بنابراین کلاس شما در بایتکد به صورت یک Stack معمولی که با Object کار میکند، دیده میشود.
۳. نتیجه نهایی: اگر متدی در این کلاس مقدار بازگشتی از جنس E داشته باشد، کامپایلر به صورت خودکار یک Casting به String در محل فراخوانی متد اضافه میکند تا برنامه بدون خطا اجرا شود.
بیشتر بدانید
-
نکته کامپایلر پاکسازی نوع نه تنها در سطح کلاسها، بلکه در سطح
Methodها نیز اتفاق میافتد. اگر متدی ورودی جنریک بگیرد، امضای آن در بایتکد تغییر کرده و به تایپ پایه (مانندObject) تبدیل میشود. -
قانون جایگزینی همیشه به یاد داشته باشید که در فرآیند پاکسازی، اولویت جایگزینی با اولین "Bound" ذکر شده است. این موضوع در طراحی معماری کلاسهای جنریک بسیار حیاتی است.
-
امنیت در بایتکد با وجود حذف اطلاعات جنریک، امنیت کد از بین نمیرود؛ زیرا کامپایلر قبلاً در مرحله
Compile Timeتمام بررسیهای لازم را انجام داده و کدهای کستینگ (Checkcast) لازم را در بایتکد تزریق کرده است.
