Generic WildCard
توضیحات جلسه
جزوه و مستندات
مفاهیم کلیدی
- Generic
مکانیزمی در زبان جاوا است که اجازه میدهد کلاسها، اینترفیسها و متدها با انواع داده مختلف یا Types بهصورت پارامتریک کار کنند. هدف اصلی آن، بررسی نوع داده در زمان کامپایل و جلوگیری از خطاهای زمان اجرا است.
- Invariance
ویژگیای در جنریکهای جاوا است که طبق آن، رابطه ارثبری بین انواع داده به نسخه جنریک آنها منتقل نمیشود.
برای مثال، با اینکه String فرزند Object است، اما List<String> فرزند List<Object> نیست.
- Wildcard
علامت سؤال ? در جنریکها بهعنوان یک جایگاه نامشخص یا Placeholder برای انواع داده استفاده میشود. زمانی از آن استفاده میکنیم که نوع دقیق داده برای ما مهم نیست یا میخواهیم متدی بنویسیم که با هر نوع ورودی کار کند.
- Type Safety
به معنای اطمینان از این است که عملیات روی دادهها با نوع صحیح انجام میشود. جنریکها با انتقال بررسی نوع داده به زمان کامپایل، امنیت کد را افزایش میدهند و از خطاهایی مانند ClassCastException جلوگیری میکنند.
- Compile-time در برابر Runtime Checking
قبل از جنریکها، بررسی نوع داده در زمان اجرا یا Runtime انجام میشد و ممکن بود باعث کرش کردن برنامه شود. با جنریکها، کامپایلر مانند یک دستیار در زمان کدنویسی، خطاها را شناسایی میکند.
موارد مصاحبه ای
- چرا در جاوا نمیتوان
List<String>را بهList<Object>نسبت داد؟
به دلیل خاصیت Invariance. اگر جاوا این اجازه را میداد، امنیت نوع داده یا Type Safety به خطر میافتاد؛ زیرا میتوانستیم در لیستی که در اصل برای String ساخته شده است، یک مقدار Double قرار دهیم. این موضوع میتوانست باعث بروز خطاهای جدی در زمان اجرا شود.
- تفاوت اصلی Wildcard با استفاده از Type Parameter مانند
<T>چیست؟
استفاده از Wildcard سادهتر است و خوانایی کد را افزایش میدهد. زمانی که در بدنه متد نیازی به ارجاع به نام نوع داده نداریم و فقط میخواهیم یک عملیات عمومی، مانند چاپ کردن، انجام دهیم، Wildcard انتخاب مناسبتری است.
- محدودیت اصلی استفاده از وایلد کارت علامت سؤال
?چیست؟
هنگام استفاده از List<?> فقط مجاز به خواندن یا Read از لیست هستیم. چون کامپایلر نوع دقیق دادههای داخل لیست را نمیداند، اجازه اضافه کردن یا Write هیچ مقداری، بهجز null، را نمیدهد تا امنیت برنامه حفظ شود.
سناریو کاربردی
فرض کنید میخواهید متدی بنویسید که هر نوع لیستی، شامل اعداد، رشتهها یا اشیای سفارشی، را دریافت کند و محتویات آن را چاپ کند.
۱. تلاش اول، روش اشتباه
اگر ورودی متد را List<Object> تعریف کنید، کامپایلر اجازه نمیدهد یک List<String> یا List<Integer> را به آن پاس دهید؛ چون آنها را زیرکلاس List<Object> نمیداند.
۲. تلاش دوم، روش درست با Wildcard
اگر ورودی متد را بهصورت List<?> تعریف کنید، متد انعطافپذیر یا Flexible میشود. در این حالت میتوانید هر لیستی با هر نوع دادهای را به آن بدهید. متد بهراحتی روی لیست پیمایش میکند و آیتمها را چاپ میکند، اما اجازه ندارد عضو جدیدی به این لیست اضافه کند.
بیشتر بدانید
- نکته کتابخانهای
در کدهای داخلی جاوا، کلاس Collections در متدهایی مانند copy و sort بهصورت گسترده از وایلد کارتها استفاده کرده است تا انعطافپذیری لازم برای کار با انواع کالکشنها فراهم شود.
- فلسفه طراحی
وایلد کارتها برای حل محدودیتهای ناشی از Invariance معرفی شدند تا همزمان با حفظ کامل امنیت نوع داده یا Type Safety، امکان نوشتن کدهای چندمنظوره و پویا فراهم شود.
- نکته فنی
فراموش نکنید که علامت سؤال ? بهتنهایی به معنای «هر چیزی» است. اما در مباحث پیشرفتهتر میتوان آن را با کلمات کلیدی extends و super محدود کرد. به این حالت، Bounded Wildcards گفته میشود.
