در جلسه قبلی با هم ساختمان داده استک یا پشته را پیاده سازی کردیم ولی همون طور که دیدم برای انواع type ها لازم هست یه کلاس جداگانه بسازیم. بعد گفتیم ما میتونیم جوری یه کلاس و ساختمان داده رو بسازیم که محدود به نوع داده نباشد.
در واقع در پیاده سازی یه ساختمان داده نباید به نوع داده محدود باشد. چون هر نوع داده ای رو باید قبول کند و بتونه ذخیره کند.
خوب توی این جلسه میخایم ببنیم چطور میتونیم کلاس MyStack جلسه پیش رو به این صورت تبدیل کنیم که به نوع داده محدود نباشد. به این نوع کلاس ها که به نوع داده محدودیتی نداشته باشند Generic گفته میشه.
همه ساختمان داده های پیشفرض جاوا به صورت جنریک پیاده سازی شدهاند.
خوب کلاس MyStack رو اگه بخواهیم به صورت جنریک بنویسم به این صورت میشود. که خط به خط توضیح داده میشه:
خوب در خط ۴ در تعریف کلاس بعد از اسم کلاس ما <T> رو نوشتیم. در واقع این کلمه به اصن صورت معرف این هست که ما یک کلاس جنریک خواهیم داشت که در آن یک type داریم که نوع آن مشخص نیست و اسم این type نا مشخص رو T گذاشتیم.
در این صورت میتونیم در این کلاس از این type نمونه بسازیم!
T t;
خوب پس کلاس MyStack در زمان نمونه سازی ازش لازم هست که برای آن یک نوع داده مشخص شود. یعنی به این صورت:
MyStack stack = new MyStack<>:(10);
خوب پس کلاس MyStack در زمان نمونه سازی ازش لازم هست که برای آن یک نوع داده مشخص شود. یعنی به این صورت:
MyStack stack = new MyStack<> (10);
در واقع در زمان نمونه سازی از کلاس MyStack ما نوع T رو مشخص میکنیم. ولی در زمان پیاده سازی MyStack فارغ از اینکه این T چه باشد ما پیاده سازی رو انجا میدهیم.
در خط ۶، نوع آرایه که قرار داده های ما را ذخیره کند را از نوع T قرار میدهیم تا بتوانیم دادههای از نوع T داخل آن بریزیم.
private final T[] array;
در خط ۱۱ همونجور که قبلا دیدم باید این آرایه دادهها را new کنیم. باید دقت کنید وقتی یک آرایه new میشود، با توجه به نوع داده و تعداد خانههای آن از حافظه، فضا جدا شده و به آن اختصاص داده میشود.
ولی چون نوع داده T نامشخص است پس در نتیجه نمیتوان به این صورت نوشت:
array = new T[size];
چون جاوا متوجه نمیشود که هر خانه از این آرایه باید به چه میزانی فضا لازم دارد.
برای رفع این مشکل ما هر کدام از خانههای آرایه رو به صورت Object که در واقع پدر همه کلاسها در جاوا هست در نظر میگیریم. و این آرایه از جنس Object را در انتها به یک آرایه از جنس T[] تبدیل یا cast میکنیم.
به این صورت:
array = (T[]) new Object[size];
در خط تابع push، ورودی این تابع همان طور که میبینید از جنس T هست. و این ورودی را در آرایه قرار میدهد.
به همین صورت سایر توابع دیگر…
خوب ببینیم طریقه استفاده از این کلاس به چه صورتی هست:
خوب همون طور که میبیند من نوع ورودی ساختمان دادم رو String گذاشتم و همان طور که میبیند ورودی و خروجی توابع push و pop هم String شدند.
خوب اجازه بدین یکبار دیگه هم تست کنیم:
خوب توی این عکس با توجه به این که نوع ساختمان داده رو Student دادیم توابع push و pop و peek ورودی و خروجی های خودشون رو تبدیل به نوع داده ما یعنی Student کردند.
دقیقا چیزی که ما میخاستیم.
حالا بیام به این صورت امتحان کنیم. بدون نوع داده!!
خوب همان طور که میبینید چون ما نوه داده خودمان رو مشخص نکردیم پس نوع داده ما به صورت Object در آمده است و برای کار کردن نیاز هست همیشه cast بکنیم ورودی ها و خروجی ها را. بنابراین همیشه لازم هست که نوع دادههای کلاسهای جنریک رو اعلام کنیم.
نکته بعدی این که ما میتونیم یک کلاس جنریک با چند نوع داده جنریک تعریف کنیم:
public class MyMap{
نکته بعدی اسم حروف T یا K یا V دلخواه هستند و میتونند هرچیزی باشند.
جلسه بعدی در مورد اینکه چطوری میتونیم همین نوع داده جنریک رو که نامعلوم هست رو محدود کنیم! یعنی حتما کلاسی که به عنوان نوع داده انتخاب میشود باید حتما یه سری ویژگی و توانایی خاصی داشته باشه صحبت میکنیم