Generic Class
توضیحات جلسه
جزوه و مستندات
مفاهیم کلیدی
- Generic Class
کلاسی است که میتواند با یک یا چند نوع داده مختلف کار کند. این نوعها بهعنوان پارامتر ورودی یا همان Type Parameter تعریف میشوند. این قابلیت باعث میشود یک کد ثابت برای انواع داده مختلف، مانند String، Integer یا کلاسهای سفارشی، قابل استفاده باشد.
- Diamond Operator
عملگر <> که برای تعریف یا مشخص کردن نوع داده در کلاسهای جنریک استفاده میشود. این عملگر به کامپایلر اعلام میکند که کلاس قرار است با چه Type Parameterای کار کند.
- Type Parameter
یک نام قراردادی یا Convention است که هنگام تعریف کلاس، بهعنوان جایگزین نوع داده واقعی قرار میگیرد. معمولاً از حروف بزرگ انگلیسی مانند T برای Type و از K و V برای Key و Value استفاده میشود.
- Type Specification
فرآیندی است که در آن، نوع دقیق داده هنگام ایجاد یک نمونه یا Instance از کلاس جنریک مشخص میشود. برای مثال، هنگام ساخت شیء با new تعیین میکنیم که T قرار است از نوع String باشد.
- Type Safety
یک مکانیزم امنیتی است که تضمین میکند فقط دادههایی از نوع مشخصشده در کلاس قرار بگیرند. این ویژگی باعث میشود اشتباهات در زمان کامپایل یا Compile-time شناسایی شوند و برنامه در زمان اجرا دچار خطا نشود.
- Compile-time Error در برابر Runtime Exception
در حالت عادی و بدون استفاده از جنریک، اشتباه در تبدیل نوع داده میتواند باعث بروز ClassCastException در زمان اجرا شود و برنامه را متوقف کند. جنریک این خطا را به زمان کامپایل منتقل میکند تا قبل از اجرای برنامه اصلاح شود.
موارد مصاحبه ای
- مزیت اصلی استفاده از Generics نسبت به کلاس Object چیست؟
استفاده از Object نیازمند تبدیل نوع دستی یا Casting است. این کار امنیت کد را کاهش میدهد و ممکن است در زمان اجرا باعث خطای ClassCastException شود. جنریکها با فراهم کردن Type Safety، نیاز به Casting را حذف میکنند و خطاها را در زمان کامپایل شناسایی میکنند.
- تایپ پارامتر در چه زمانی مشخص میشود؟
نوع دقیق داده یا Type زمانی مشخص میشود که برنامهنویس بخواهد یک نمونه یا Instance از آن کلاس ایجاد کند.
- آیا میتوان مستقیماً یک آرایه از نوع جنریک، مانند
new T، ساخت؟
خیر. در جاوا امکان نمونهسازی مستقیم از Type Parameter برای آرایه وجود ندارد. برای حل این مشکل باید از Reflection و متد Array.newInstance استفاده کرد و نوع کلاس، یعنی Class<T>، را به آن پاس داد.
- منظور از Raw Use در کلاسهای جنریک چیست؟
یعنی استفاده از یک کلاس جنریک بدون تعیین نوع داده داخل علامت <>. این کار باعث میشود کامپایلر هشدار یا Warning بدهد؛ چون امنیت تایپی که جنریک فراهم میکند، در این حالت نادیده گرفته شده است.
- چرا در پیادهسازی داخلی مجموعههای جنریک از انوتیشن SuppressWarnings استفاده میشود؟
زمانی که برنامهنویس از امنیت تبدیل نوع یا Casting در کدهای بازنویسیشده اطمینان دارد اما کامپایلر همچنان هشدار میدهد، با استفاده از @SuppressWarnings("unchecked") به کامپایلر اعلام میکند که بررسیهای لازم انجام شده و هشدار نادیده گرفته شود.
سناریو کاربردی
در این آموزش، یک کلاس DynamicArray که قبلاً با نوع داده Object نوشته شده بود، با استفاده از جنریکها بازنویسی شد.
۱. ابتدا کلاس بهصورت DynamicArray<T> تعریف شد تا بتواند هر نوع دادهای را بپذیرد.
۲. مشکل عدم امکان ساخت مستقیم آرایه با new T[]، از طریق دریافت Class<T> در سازنده یا Constructor و استفاده از ابزار Reflection حل شد.
۳. نتیجه این شد که وقتی یک DynamicArray<String> ساخته میشود، متد get مستقیماً خروجی String میدهد. اگر برنامهنویس بخواهد بهاشتباه یک عدد از نوع Integer در آن قرار دهد یا خروجی را در متغیری با نوع نامرتبط ذخیره کند، کامپایلر بلافاصله خطا میدهد و مانع اجرای کد اشتباه میشود. این کار باعث حذف کدهای اضافی برای Casting و افزایش امنیت کل پروژه شد.
بیشتر بدانید
- قرارداد نامگذاری
طبق استانداردهای جاوا، بهتر است برای Type Parameterها از حروف تککاراکتری معنادار استفاده کنید؛ مانند T برای انواع عمومی، E برای عناصر لیست یا Element، و K و V برای نگاشتها یا Key/Value.
- تضمین کامپایلر
جنریکها در جاوا در واقع یک لایه محافظتی برای برنامهنویس هستند. کامپایلر تضمین میکند که اگر نوع داده را مشخص کرده باشید، دیگر نیازی به نگرانی درباره خطاهای تبدیل نوع در زمان اجرا نخواهید داشت.
