آموزش جاوا قسمت اول

*بانو بهار*

کاربر نگاه دانلود
کاربر نگاه دانلود
عضویت
2016/08/15
ارسالی ها
3,937
امتیاز واکنش
10,965
امتیاز
804
محل سکونت
میان شکوفه‌ها
نکته‌ای که هست اینکه به همون اندازه که یک طراحی شی‌گرای خوب باعث کاهش پیچیدگی و مدل کردن ساده مسئله هست، یک طراحی نامناسب با استفاده از OOP یه فاجعه رو به وجود میاره. پس یه طراحی خوب لازم هست.
این نکته رو هم بگم که اصلا دنبال این نیستیم که شی‌گرایی محض داشته باشیم، ولی هدف اصلی ما این هست که ۴ اصل اساسی شی‌گرایی رو در کنار هم در پیاده‌سازی استفاده کنیم.
اما این ۴ اصل:
اصول برنامه نویسی شی گرا (oop)
۱-تجرید یا انتزاع (Abstraction)
۲-کپسوله سازی (Encapsulation)
۳-ارث‌بری (Inheritance)
۴-چند‌ریختی (Polymorphism)
شاید در مورد این اصول خیلی شنیده باشید و استفاده هم بکنید ولی گفتنش خالی از لطف نیست
۱-تجرید یا انتزاعی (Abstraction)
در oop ما سه مفهوم کلاس (class) و موجودیت (Object) و نمونه (instance)
همه موجودیت ها در یک الگو شی‌گرا باید به صورت انتزاع یا abstract باشه. یعنی اینکه توی دنیای واقعی همچین موجودیتی وجود نداشته باشه و فقط توی ذهن ما باشه.
مثلا انسان، کاربر، کتاب.
در واقع وقتی شما کلمه انسان رو می‌شنوید یه مدلی توی ذهنتون شکل میگیره که دارای یه سری خصیصه (attribute) و توانایی (method) هست ولی شخص خاصی توی ذهنتون نیست. در واقع شما دارین به صورت انتزاعی فکر می‌کنید. هدف در شی‌گرایی این هست که این مفهوم و طرز فکر را پیاده سازی کنیم.

پس تا اینجا موجودیت‌های سیستم ما همیشه انتزاعی هستند. هر موجودیت یک کلاس هست ولی هر کلاس یک موجودتی نیست. بعضی از کلاس‌ها برای این ساخته ‌می‌شوند که ابزاری در اختیار ما بگذارن. مثلا کلاس‌های utils یا کلاس math و … .
توی یک سیستم ما میتونیم nتا موجودیت داشته باشیم. ما میتونیم از هر‌کدوم از این موجودیت‌ها به هر تعداد نمونه داشته باشیم. مثلا از موجودیت انسان می‌تونیم نمونه محمد، علی و… را داشته باشیم. دقت کنید برعکس موجودیت که انتزاعی بودند نمونه‌ها باید واقعی باشند و بتونیم به یک عامل واقعی نسبت بدیم.
۲- کپسوله‌سازی(Encapsulation)
این مفهوم خیلی خیلی نزدیک به مفهوم جعبه‌سیا (black box) هست. در واقع ما باید موجودیت‌ها یا کلاس‌ها رو به نحوه‌ای پیاده سازی کنیم که فقط ورودی و خروجی‌ها برای اعضای بیرونی قابل نمایش باشند و اعضای داخلی کلاس محافظت شوند.
برای مثال یک اتومبیل رو فرض کنید، همه ما میدونیم این اتومبیل داری فرمان و گاز و … هست و میدونیم در صورت استفاده از اون‌ها چه اتفاقاتی رخ می‌دهد ولی اینکه این اتفاقات چطوری انجام می‌شود اطلاع نداریم. مثلا اگه گاز بدهیم می‌دونیم ماشین جلو میرود ولی اینکه چه اتفاقاتی می‌افتد تا ماشین جلو برود نمی‌دادیم و برای ما هم مهم نیست.
در واقع در طراحی موجودیت‌ها و کلاس‌ها هم باید به این نکته توجه کرد که باید چندین لایه از این کپسوله سازی رعایت شود و فقط اجزایی قابل دسترسی از بیرون باشند که نیاز هست و سایر اجزا محدود شوند. که تعریف این سطح دسترسی در جاوا به صورت public یا private یا protected و یا محدویدت در سطح یک پکیج ایجاد میکنیم.
کپسوله سازی این کمک رو میکنه که بدون متوجه شدن از پیچیدگی های بخش‌های مختلف بتونیم از اون‌ها استفاده کنیم. کپسوله سازی می‌تونه تا چندین لایه انجام شود و هرچه بیشتر شود به اصطلاح گفته میشود ماژولارتر می‌شود.
۳-ارث‌بری (Inheritance)
توضیحات این قسمت به موقع خودش کامل گفته میشه فقط این مورد رو در مورد ارث‌بری باید بدونیم اینکه ارث‌بری با اهداف زیادی اضافه شده ولی مهمترین اون‌ها به این برمیگرده که قابلیت سلسه‌مراتب بین موجودیت‌ها را به ما می‌دهد. مورد بعدی اینکه قابلیت بازنویسی یک موجودیت را به ما می‌دهد. که کامل این دو مورد و موارد دیگه بحث می‌شود.
۴- چند‌ریختی (Polymorphism)
این مورد هم شبیه مورد ارث‌بری در زمان خودش به طور کامل توضیح داده می‌شه فقط اگه بخواهیم توضیح مختصری بدیم اینکه این قسمت تاکید بر روی این داره که ما به موجودیت‌ها و کلاس‌ها قابلیت بدیم. یعنی اینکه مثلا بگوییم این موجودیت قابلیت A را دارد ولی اینکه چگونه آن را انجام می‌دهد مد نظر ما نباشد و هر نمونه می‌تواند به هر نحوه‌ای این قابلیت A را پیاده‌سازی کند ولی همه این نمونه‌ها قابلیت A را دارا می‌باشند.
مثلا یک انسان، پرنده و یک خزنده را در نظر بگیرین. همه قابلیت حرکت کردن را دارند ولی نحوه پیاده‌سازی آن‌ها متفاوت هست. انسان راه می‌رود، پرنده پرواز می‌کند.
این مفهوم همان چند ریخته‌گی هست که یه قابلیت به چند شکل ظاهر می‌شود. البته این یک نمود از چندریختگی هست که بیشتر در موردش صحبت میشه.
تا اینجا ما چهار اصل شی‌گرایی رو گفتیم
که در همه زبان‌های شی‌گرا یکسان هست
در جلسه‌ای بعدی نحوه پیاده‌سازی و استفاده از این اصول رو میگیم



Rea
 
  • پیشنهادات
  • *بانو بهار*

    کاربر نگاه دانلود
    کاربر نگاه دانلود
    عضویت
    2016/08/15
    ارسالی ها
    3,937
    امتیاز واکنش
    10,965
    امتیاز
    804
    محل سکونت
    میان شکوفه‌ها
    خوب بریم سراغ کد نویسی:
    این کد در واقع متن Hello رو داخل کنسول یا همون output برای شما چاپ میکنه.
    تابع main که همیشه به همین صورت ظاهر میشه در واقع اولین نقطه اجرا کدتون هست. یعنی همیشه کدتون با تابع main شروع میشه و امضای این تابع دقیقا همیشه به این شکل هست:


    public static void main(String args[])
    که بعدا در مورد بخش های مختلفش صحبت می‌کنیم.

    نکته بعدی اینکه دقت کنید تابع main داخل یک کلاس قرار داره. در واقع در جاوا هر کلاس در یک فایل قرار میگیره که همیشه اسم فایل و اسم کلاس باید یکی باشد. در اینجا ما این کد رو داخل فایل Main.java نوشتیم.

    نکته بعدی اینکه جاوا case sensitive هست یعنی به کوچک و بزرگ بودن حروف حساس هست.
    نکته بعدی اینکه توی زیان‌های شی‌گرا از کلمه تابع استفاده نمی‌کنند و بجاش از کلمه متد استفاده میشه. یعنی در واقع تابع main از این به بعد میشه متد main!!
    خوب الان یه مثال دیگه با هم ببینیم تا بیشتر در جریان قرار بگیرین:

    13.jpg


    توی این کد ما دو عدد از کاربر (از قسمت output) دریافت کردیم باهم جمع کردیم و در خروجی چاپ کردیم. ولی چطوری؟
    فایل جدیدی به نام Main2.java ساختیم و داخل اون کلاس Main2 رو میسازیم. برای اینکه هربار نخواین امضای main رو بنویسید کافیه بنویسید psvm و دکمه tab کیبرد رو بزنید! خود IDE تکمیل میکنه!

    خوب توی خط ۵ ما داریم نمونه‌ای به نام input از کلاس Scanner میسازیم تا بتونیم ازش استفاده کنیم. (عجله نکنید بعدا توضیح میدیم این نمونه ساختن به چه نحوه‌ی هست)
    توی خط ۹ متنی را چاپ میکنیم و در خط ۱۰ یک عدد از کاربر دریافت می‌کنیم و داخل متغییر number1 میریزیم.
    و در آخر هم حاصل را چاپ میکنیم.
    خوب دوستانی که تازه شروع کردن میتونند
    برای جلسه بعدی برنامه‌آی بنویسید که ابتدا یک عدد بگیرد بعد یکی از علامت‌های + - * و بعد عدد دوم. و حاصل این دو عدد با توجه به علامت گرفته شد هرا چاپ کنه.
    هدف ای گفتن این دوتا مثال فقط این بود یکم آشناییت پیدا کنید
    خوب بریم سراغ بحث اصلی این جلسه که در مورد ۲ اصل اول بحث گذشته یعنی abstraction صحبت کنیم.
    خوب قبل از اینکه شروع کنیم سوالی ازتون میپرسم که بهش فک کنید. توی مثال بالا Scanner یک موجودیت بود یا یک کلاس؟ (با توجه به جلسه قبلی میتونید پاسخ بدین)
    در موردش فک کنیم اخر جلسه صحبت کنیم
    خوب، مهمترین نکته‌ای که در طراحی شی‌گرا باید بهش دقت داشته باشیم فهمیدن موجودیت‌های سیستم(پروژه‌ای که به ما داده شده) هست. در واقع موجودیت ها همان عامل‌های انتزاعی هستند که جلسه اول در مورد اون‌ها صحبت کردیم. پس قدم اول ما پیدا کردن موجودیت‌های سیستم هست.�
    مثال: موجودیت های سیستم ثبت‌نام دانشگاه
    ۱- دانشجو
    ۲- درس
    ۳- استاد
    ۴- دانشگاه
    سوالی که پیش میاد اینکه آیا واقعا دانشگاه موجودیت هست؟
    با اینکه ما فقط یک نمونه از اون رو توی سیستم داریم. جواب این سوال بله هست. موجودیت بودن یا نبودن رو تعداد نمونه های اون نشون نمیده.
    پیدا کردن موجودیت‌ها و مدل کردن سیستم کاری هست که به مرور زمان و تجربه خیلی ساده‌تر میشه ولی نکاتی داره که باید توی طراحی در نظر گرفت و خیلی مهم هستند که با توجه به اینکه این اموزش، اموزش جاوا هست ما روی این موضوع وقت نمیگذاریم.
    بعد از فهمیدن موجودیت‌های سیستم لازم هست خصیصه ها یا ویژگی‌های موجودیت و توانایی آن‌ها را پیدا کنیم. از این به بعد به خصیصه ها field می‌گیم و توانایی‌ها همون متدهای موجودیت هستند.
    خوب پس ما باید برای تک تک این موجودیت ها field ها رو مشخص کنیم و بعد بریم سراغ متدها
    خوب پس کلاسی به نام Student میسازیم به این صورت:

    14.jpg


    تا اینجا ما این field ها را برای دانشجو در نظر گرفتیم. شاید بعدا بهش اضافه کنیم.
    خوب یک توانایی یا متد به نام printName اضافه می‌کنیم که اسم و فامیل را برای ما چاپ می‌کند به این صورت:



    15.jpg


    خوب الان بریم ببینیم چطوری میتونیم از این موجودیت دانشجو استفاده کرد. من نمونه‌ای به نام ali از موجودیت دانشجو به این صورت می‌نویسم.

    Student ali = new Student();
    این عبارت همون طور که میبینید از ۴ جز اصلی تشکیل شده است. از سمت چپ به راست:

    Student در واقع نوع موجودیت رو مشخص می‌کند و ali اسم نمونه هست که شما میتونید هر اسمی خواستین بگذارین. در واقع تا اینجا شبیه ساختن یه متغییر از جنس int هست:

    int a;
    که در واقع متغییری به نام a داریم از جنس int میسازیم.
    کلمه Student در واقع نوع موجودیت رو مشخص می‌کند و ali اسم نمونه هست که شما میتونید هر اسمی خواستین بگذارین. در واقع تا اینجا شبیه ساختن یه متغییر از جنس int هست:



    int a;
    که در واقع متغییری به نام a داریم از جنس int میسازیم.
    من یه نمونه دیگه به نام std1 هم از کلاس Student میسازم:



    Student std1 = new Student();
    خوب ما میتونیم به این صورت به اجزای یک نمونه دسترسی داشته باشیم:

    6.jpg


    ما توی خط ۹ ویژگی‌ id نمونه ali را مقدار ۱ قرار دادیم و در خط بعدی برای ویژگی name نمونه ali مقداری رو مشخص کردیم. خط ۱۲ و ۱۳ برای نمونه std1 و توی خط های انتهای مقدار آن ها را چاپ کردیم.

    توی خط ۲۰ هم متد printName رو فراخوانی کردیم که درواقع اسم و فامیل کاربر را برای ما چاپ میکنه
    فقط دقت کنید توی خط ۱۸ ما داریم field رو مقدارش رو چاپ میکنیم که مقدار دهی نکردیم بنابراین جاوا مقدار پیش فرض یعنی null رو برای ما چاپ میکند.
    نکته که همه دوستان می‌دونند ولی لازم هست بگم اینکه هر نمونه ویژگی‌های خودش رو داره و جایگاه ذخیره‌سازی اون‌ها در حافظه متفاوت هست. یعنی id نمونه اول با id نمونه دوم و همه نمون های دیگر متفاوت هست.
    تا اینجا برای این جلسه کافی هست. جلسه بعدی یا میگیریم این موجودیت رو چطور کپسوله کنیم و مطالب مرتبط با اون رو میگیم.
    میدونم خیلی خیلی بحث‌ها ابتدایی هستند ولی کم کم سرعت یادگیری رو بالا میبریم که همه بتونند استفاده کنند پس کمی صبور باشین. به جاهای خوب هم میرسیم!
    فقط همون طور قول داده بودم اخر هر جلسه چندتا از نکات نگارشی توی زبان جاوا رو میگم. دقت داشته باشید که رعایت نکردن این موارد تاثیری در کامپایل شدن یا نشدن کدتون ندارد ولی برای نوشتن استاندارد لازم هست رعایت بشه.
    1) نام کلاس‌ها با حرف بزرگ شروع می شوند. اگر نام کلاس شامل دو کلمه یا بیشتر باشد حرف اول کلمات را بزرگ می نویسم.
     

    *بانو بهار*

    کاربر نگاه دانلود
    کاربر نگاه دانلود
    عضویت
    2016/08/15
    ارسالی ها
    3,937
    امتیاز واکنش
    10,965
    امتیاز
    804
    محل سکونت
    میان شکوفه‌ها
    در برنامه‌نویسی شی‌گرا قانوی وجود دارد با این مفهوم که همه چیز باید کپسوله و مخفی شود مگه ایمکه خلافش ثابت شود. یعنی هر جزیی باید مخفی و سطح دسترسی نداشته باشد مگه اینکه واقعا لازم داشته باشیم.
    خوب قبل از اینکه در مورد این قانون حرف بزنیم اول در مورد سطح دسترسی‌ها صحبت کنیم.
    هر field یا method در داخل کلاس خود همیشه در دسترس هست. و اعضای یک کلاس به همه field یا method های کلاس خود بدون هیچ محدودیتی دسترسی دارند.
    مثلا در عکس قبل داخل متد printName شما می‌تونید هرکدوم از fieldها را فراخوانی کنید و استفاده کنید.
    ی public و private دو مورد از سطح دسترسی‌ها هستن که این جلسه در موردشون صحبت می‌کنیم.
    به طور کلی اگر یک field یا method به صورت public تعریف شود به این معنی هست که دسترسی به ان از بیرون هم ممکن هست. یعنی اگر من داخل کلاس Student مقدار id را به این صورت تعریف کرده باشم:



    public int id;
    می‌تونیم به ویژگی‌ id به این صورت دسترسی داشته باشم:

    Student ali = new Student();
    ali.id = 1;

    خوب ببینیم که اگه یک field یا method به صورت private تعریف شود چه اتفاقی می‌افتد. مثلا ما ویژگی name موجودیت Student رو به صورت private مینویسیم:

    private String name;
    وقتی یک field یا method به صورت private تعریف میشه در واقع دسترسی اون رو ما محدود کردیم به اجزای داخلی اون کلاس و از بیرون قابل دسترسی نیست یعنی نمیتونیم به این صورت بنویسیم:

    Student ali = new Student();
    ali.name = “ali”;

    سطح دسترسی‌های دیگه هم وجود دارد که در جلسات بعدی درموردشون صحبت میکنیم.
    برگردیم سراغ قانون که اول جلسه گفتیم در مورد اینکه همه چیز باید مخفی شود پس طبق این قانون ما باید همه field یا method ها را به صورت private تعریف کنیم.
    پس به این صورت میشه:

    34.jpg


    خوب ولی همون جور که میدونید ما متد printName() رو برای این نوشتیم که بتونیم اسم و فامیل را برای یک نمونه چاپ گند و لازم هست از بیرون کلاس هم فراخوانی شود پس نمی‌تواند private باشد پس باید تبدیل به public شود.

    در واقع نوع سطح دسترسی method ها بر میگرده به منطق برنامه که می‌نویسیم. شاید method وجود داشته باشد که لازم نباشد شما public تعریف کنید.

    ولی در مورد field ها همه باید private باشند!! خوب الان دوتا سوال پیش میاد اینکه چرا اصلا باید private باشه؟! و دوم اینکه چطوری پس بهشون مقدار بدیم یا مقدارشون رو بخونیم.

    سوال اول رو در موردش فکر کنید آخر جلسه در موردش حرف میزنیم ولی در مورد سوال بعدی اینکه چون field ها به صورت private هستند پس لازم هست برای اون ها یک متد نوشته شود که مقدارشون رو بخونیم و یک متد برای تغییر مقدار اون ها داشته باشیم به این صورت.

    35.jpg




    Read m
     

    *بانو بهار*

    کاربر نگاه دانلود
    کاربر نگاه دانلود
    عضویت
    2016/08/15
    ارسالی ها
    3,937
    امتیاز واکنش
    10,965
    امتیاز
    804
    محل سکونت
    میان شکوفه‌ها
    در جاوا ما ۸ نوع دیتاتایپ primitive داریم که عبارت‌اند از:

    byte
    short
    int
    long
    float
    double
    char
    boolean

    و سایر تایپ های دیگه جز reference قرار میگیرند. مثلا هر نمونه‌ای که از کلاس Student که جلسه قبلی تعریف کردیم. با این تقسیم بندی میتونیم ویژگی هرکدوم رو به راحتی گفت.

    دسترسی به حافظه:

    برای primitive ها وقتی شما متغییر primitive را فراخوانی میکنید دقیقا به خانه‌ای از حافظه میرین که مقدار این متغییر در ان‌جا ذخیره شده است.

    برای reference با فراخوانی در واقع شما به خانه‌ای از حافظه میرین که آدرس از حافظه در اونجا قرار داره که اطلاعات نمونه مورد نظر ذخیره شده است.

    انتصاب مقدار (Assignment):

    در primitive ها، با انتصاب یک مقدار در واقع واقعا مقدار اون متغییر عوض میشود ولی در reference ها فقط آدرسی که اشاره شده است تغییر می‌کند.

    در واقع به زبان خیلی ساده‌تر بخوایم بگیم اینکه متغییر‌های reference حالت اشاره‌گر دارند.

    مقایسه:

    شما میتونید دو متغییر primitive رو با استفاده از علائم مقایسه‌ای مقایسه کنید:

    int a = 9;
    int b = 10;
    a == b, a<= b, …
    ولی اگر برای دو متغییر reference از این روش استفاده کنید در واقع شما دارین آدرس‌هایی که به هم اشاره میکنند را با هم مقایسه می‌کنید:

    String a = “a”

    String b = “a”

    a == b ⇒ false
    برای مقایسه دو متغییر reference باید از متد equals استفاده کرد:

    a.equals(b)

    دقت داشته باشید برای مقایسه مثلا دو نمونه از کلاس student لازم هست شما متد equals کلاس Student را پیاده سازی کنید

    40.jpg


    در مورد نحوه پیاده‌سازی متد equals باید توجه کرد چون ورودی این متد به صورت object هست لازم هست اول تبدیل به نمونه Student شود و بعد بر اساس معیار ما شرط تساوی چک شود. مثلا در عکس بالا شرط تساوی دو نمونه Student به این صورت هست که دارای id یکسانی باشد. شاید شما بگین دو نمونه از کلاس Student وقتی برابر هستند که usernmae های یکسانی داشته باشد. شما میتونید هر نوع شرط تساوی را خودتون پیاده سازی کنید.

    نکته بعدی اینکه امضای متد equals باید به همین صورت باشد و نباید تغییر کند.

    بازگشت (return)

    وقتی شما یک متغییر primitive رو return میکنید در واقع شما مقدار اون رو برمیگرده ولی وقتی شما یک نمونه reference را return میکنید در واقع آدرس اون نمونه برگشت داده میشود.



    مقدار پیشفرض:

    متغییرهای primitive مقدار پیشفرض دارن که متفاوت هست مثلا برای متغیرهای عددی مقدار صفر و برای نوع boolean مقدار false هست:

    int a;
    System.out.println(a);
    برای نمونه های reference مقدار پیشفرضی وجود ندارد و null هستند:

    Student a;
    System.out.println(a);
    پذیرش null:
    به متغییرهای primitive نمی‌توان مقدار null نسب داد ولی به متغییرهای reference میشود مقدار null داد در واقع معنی null بودن مقدار یک متغییر این هست که به هیج‌کجا از حافظه اشاره نمی‌کند.

    int a = null; //error
    Student a = null;
    برای روشن شدن مسئله به مثال های زیر دقت کنید (حتما امتحان کنید و خروجی را ببینید):

    41.jpg


    42.jpg
     
    آخرین ویرایش توسط مدیر:

    *بانو بهار*

    کاربر نگاه دانلود
    کاربر نگاه دانلود
    عضویت
    2016/08/15
    ارسالی ها
    3,937
    امتیاز واکنش
    10,965
    امتیاز
    804
    محل سکونت
    میان شکوفه‌ها
    همچنین شما می‌تونید از کلاس‌های نیز آرایه بسازین:

    Student[] students = new Student[3];
    دقت کنید وقتی آرایه‌ای از کلاس ها میسازیم، در واقع خانه‌های حافظه را به اندازه آرایه رزرو می‌کنیم ولی در ابتدا مقدار این خانه ها برابر nullهست.

    System.out.println(students[0].getName());
    بنابراین لازم هست برای استفاده از هر خانه ابتدا ان را new کنیم:



    students[0] = new Student();
    System.out.println(students[0].getName());
    همچنین ما میتوانیم یک آرایه را با مقدار دهی اولیه تعریف کنیم:

    int[] array = {1, 2, 5, 7, 9};
    System.out.println(array[3]);
    در جلسه بعدی بحث آرایه ها رو بیشتر باز میکنیم و نکات مربوط به اون رو میگیم و همینطور در مورد آرایه‌های دو بعدی صحبت می‌کنیم.

    قواعد نگارشی جاوا:



    ۱- متغییرهای که به صورت ثابت تعریف می‌شوند همیشه تماما با حروف بزرگ نوشته می‌شود و برای فاصله از ـ استفاده میشود:

    public final static int NUMBER =10
    public final static int STUDENT_NUMBER =10
    ۲- اسم متغییرهای‌ که به صورت آرایه تعریف می‌شوند بهتر است به صورت جمع اسم‌:ذاری شود:

    int[] numbers = new int[7];
    Student[] students = new Student[9];


    ۳- متدهایی که برای ما به دنبال چیز خاصی میگردنند را بهتر است در نام گذاری آن‌ها از کلمه find استفاده شود:

    vertex.findNearestVertex()
    problem.findBestSolutio


    Re
     

    *بانو بهار*

    کاربر نگاه دانلود
    کاربر نگاه دانلود
    عضویت
    2016/08/15
    ارسالی ها
    3,937
    امتیاز واکنش
    10,965
    امتیاز
    804
    محل سکونت
    میان شکوفه‌ها
    جلسه قبل در مورد آرایه‌ها صحبت کردیم و یادگرفتیم چطور میشه یک آرایه را تعریف کرد. نکته‌ای که تنها از بحث جلشه پیش باقی ماند این هست که آرایه به صورت final چه وضعیتی پیدا میکند.

    همان طور که قبلا گفته شد وقتی یک متغییر Reference به صورت final تعریف می‌شود قابلیت new شدن مجدد را ندارد پس بنابراین نمی‌توان آرایه را new کرد ولی می‌توان مقادیر خانه‌های آرایه را تغییر داد. حتی اگر جنس خانه‌های آرایه به صورت primitive باشند.

    final int[] array = new int[5];
    array[0] = 2;
    final Student[] students = new Student[5];
    students[0] = new Student();


    همون که بالا گفته شد آرایه‌ها خاصیت Reference دارند و این متغییرها خاصیت Reference که چند جلسه قبلی گفته شده را دارند حتی اگر جنس خانه‌های آن primitive باشد.

    همچنین تعریف آرایه ها به عنوان آرگومان ورودی و خروجی به این صورت هست:

    public int[] incValue(int[] array){
    for(int i = 0; i < array.length; i++){
    array = array + 1;
    }
    return array;
    }
    که در واقع این متد ید آرایه دریافت می‌کند و به تک تک خانه‌های آن یک واحد اضافه کرده و ان را return می‌کند.

    نحوه فراخونی این متد هم به صورت زیر است:

    final int[] array1 = {1, 3, 2, 5, 8};
    final int[] array2 = incValue(array1);


    System.out.println(Arrays.toString(array1));
    System.out.println(Arrays.toString(array2));
    سوالی که پیش میاد این هست که اگه هر دو آرایه چاپ شوند گـه مقداری نمایش داده خواهد شد؟

    جواب این سوال رو بهش فک کنید و یا اجرا کنید (اخر جلسه در موردش حرف میزنیم)

    بل از اینکه به ادامه بحث بریم در مورد کلاس Arrays صحبت کنیم. این کلاس یک کلاسی هست که شامل یک سری متد به صورت static هست که در واقع ابزار لازم برای کار با آرایه‌ها را در احتیار ما می‌گذارد.

    مثلا در مثال بالا ما از متد toString این کلاس استفاده کردیم که یک آرایه را برای ما چاپ می‌کند. این کلاس دارای متذهای خیلی خیلی مفید هستند که به صورت بهینه پیاده سازی‌ شده‌اند و می‌ةوان از آن‌ها استفاده کرد.

    متدهای برای نمایش، برای جستجو، مرتب‌سازی، کپی‌کردن و … هست. پیشنهاد می‌کنم همیشه از این کلاس استفاده کنید.

    کلاس‌هایی که همه توابع آن‌ها به صورت static هستند و در واقع ابزاری را در اختیار ما قرار می‌دهند به آن‌ها اصطلاحا کلاس‌ای utils گفته‌ می‌شود.

    اگر بیشتر در مورد این نوع کلاس‌ها بخواهیم صحبت کنیم می‌بینیم این کلاس‌های utils دارای سازنده به صورت private هستند. در واقع با تعریف سازنده به صورت private این شرایط را فراهم میکنیم که از بیرون کلاس، هیچ کس اجازه ساخت نمونه از کلاس utils را ندارد. و اصولا ه منیازی بهش نداریم چون همه متدها به صورت static هست که در واقع بدون نمونه سازی می‌توان از آن‌ها استفاده کرد.

    61.jpg


    فقط دقت شود کسی از بیرون این کلاس اجازه ساخت نمونه را ندارد ولی از داخل این کلاس میتوان یک نمونه از خود کلاس ساخت.

    شبیه کلاس Arrays می‌توان کلاس معروف Math را تعریف کرد که در واقع ابزار ریاضی را در اختیار ما قرار می‌دهد. در واقع تمامی توابع اولیه ریاضی را در این کلاس utils می‌تونید پیدا کنید.

    خوب بریم سراغ آرایه های دوبعدی و در واقع چندبعدی. آرایه‌ها دوبعدی رو توضیح میدیم و شما میتونید از آرایه‌ها با ابعاد بزرگتر از همین روش استفاده کرد.

    آرایه های با ابعاد بزرگ عملا کاربردی نیستن به جز در موارد خاص. حتی آرایه‌های دوبعدی نیز کاربردی خیلی کمی در پیاده‌سازی‌های شی‌گرا دارد.

    در جاوا می‌تونید به این صورت آرایه دوبعدی تعریف کنید:

    int[][] array = new int[2][3];
    array[0][0] = 6;
    و هم چنین به این صورت می‌توانید مقدار دهی اولیه بکنید:

    int[][] array = {{1, 2, 3}, {3, 4, 5}};
    که در واقع دارای دو سطر که هر سطر آن دارای ۳ ستون هست.

    در جاوا علاوه بر ساختن آرایه‌ها به صورت بالا که به تعداد منظم سطر و ستون دارند یعنی هر ردیف داری تعداد ستون مشخصی هست (مثلا در مثال بالا هر سطر دقیقا ۳ ستون دارد) میتوان آرایه‌های تعریف کرد که تعداد ستون متفاوت داشته باشد.

    علت این امر هم چیزی نیست در مفهوم آرایه‌ها. در واقع جاوا فقط آرایه یک بعدی دارد!! ولی میتوان هر خانه این آرایه یک بعدی را شما یه آرایه قرار بدین!! به این صورت می‌تونید آرایه دو بعدی بسازین یا با ابعاد بیشتر:

    int[][] array = new int[3][];
    array[0] = new int[2];
    array[1] = new int[5];
    array[2] = new int[1];
    در واقع الان ما یه آرایه دو بعدی که دارای سه سطر هست داریم که سطر اول آن ۲ ستون و سطر بعدی ۵ ستون و سطر آخر یک ستون دارد!

    و به این صورت هم میتوان با مقدار دهی اولیه این آرایه را مقدار دهی کنیم:

    int[][] array = {{1,2}, {1,2,3,4,5}, {1}};
    همچنین برای چاپ این آرایه می‌توان به این صورت عمل کرد:

    for(int i = 0; i < array.length; i++){
    for(int j = 0; j < array.length; j++)
    System.out.print(array[j] + “ “);
    }
    System.out.println();
    }
    که در واقع array.length تعداد سطرهای آرایه را برمیگرداند و array.length تعداد ستون‌های سطر iام را نشان می‌دهد.

    نکته انتهایی این بخش هم این هست که آرایه ها در جاوا دارای طول ثابتی هستند و نمیتوان بعد از تعریف طول آن‌ها را تغییر داد مگر اینکه از اول new شوند. در جلسات آینده در مورد list که نوعی‌ از collection ها هستن که در واقع list در اختیار ما قرا میدهد که دارای طول متغییر هستند صحبت می‌کنیم.

    این جلسه را زودتر تموم میکنیم و وارد بخش بعدی نمیشیم. چون بحث بعدی یکم گسترده هست و نیاز به یک جلسه کامل دارد

    در صورتی که سوالی هست از این جلسه من در خدمت هستم

    در انتها هم بنده فراموش کردم. جواب سوال در داخل آموزش هم به این صورت هست:

    خروجی کد:

    [2, 4, 3, 6, 9]
    [2, 4, 3, 6, 9]



    Read mor
     

    *بانو بهار*

    کاربر نگاه دانلود
    کاربر نگاه دانلود
    عضویت
    2016/08/15
    ارسالی ها
    3,937
    امتیاز واکنش
    10,965
    امتیاز
    804
    محل سکونت
    میان شکوفه‌ها
    و به طور کلی وقتی ارث‌بری کاربردی می‌شود که موجودیت‌های ما وجه اشتراک داشته باشند و برای تکرار نکردن این ویژگی‌ها از ارث بری استفاده میکنیم.

    شبیه پدر و پسر که چون خیلی از ویژگی‌ها رو پسر دارد نیاز به گفتنش نیست فقط کافی هست بگیم پدر این پسر فلان کس هست تا ما همه ویژگی‌ها و توانایی‌های پدر را به پسر نسبت بدهیم.

    خوب برای روشن شدن موضوع اول بریم سراغ مفهوم پدر و فرزند در ارث‌بری:

    کلاس پدر یا Superclass در واقع کلاسی هست که قرار هست ما از ان ارث ببریم و ویژگی‌های ان را برای خودمان کنیم و استفاده کنیم. در جاوا هر کلاسی می‌تواند به عنوان کلاس پدر انتخاب شود (به جز موارد خاص) بنابراین شرایط خاصی وجود نخواهد داشت:

    public class Animal {

    }
    کلاس فرزند یا Subclass در واقع کلاسی هست که از یک پدر ارث میبرد. در جاوا ارث‌بری هم برای ویژگی‌ها و هم برای توانایی‌ها هست. در واقع کلاس فرزند هم ویژگی‌ها و هم توانایی‌های پدر را به ارث می‌برد.

    public class Dog extends Animal{

    }
    در جاوا از کلمه کلیدی extends برای به ارث بردن استفاده می‌شود. در این مثال کلاس Dog از کلاس Animal ارث بـرده می‌شود.

    اجازه بدید بگویم ما اشیاء سگ و گربه را داریم. سگ و گربه هر دو حیوانند بنا بر این به طور طبیعی ما می‌توانیم یک سوپر کلاس به نام حیوان درست کنیم که ویژگی‌های همه حیوانات را داشته باشد و سپس ویژگی‌های خاص را برای یک سگ و یک گربه بسازیم.

    اجازه دهید با سوپر کلاس یعنی کلاس حیوان شروع کنیم. اینجا می توانیم متغیر ها و متد هایی رو دست کنیم که همه حیوانات می‌توانند داشته باشند. هم اکنون ما همه چیز را ساده می‌کنیم و فقط یک متغیر و دو متد که همه حیوانات می‌توانند داشته باشند را درست می کنیم.

    71.jpg


    کلاس فرزند یا همان کلاس dog هم به این صورت:

    72.jpg


    خوب الان میتونیم به اینصورت نوشت:

    public static void main (String[] args){
    Dog d = new Dog();
    d.sleep();
    }
    خوب همان طور که میبیند کلاس dog متدی به نام sleep ندارد ولی چون ما از کلاس animal ارث بردیم پس کلاس فرزند هم دارای توانایی پدر نیز می‌شود.

    به طور کلی ویژگی‌ها و متدهای که به صورت public تعریف شده‌اند در دسترس نمونه‌هایی که از کلاس فرزند ساخته می‌شود قرار می‌گیرد.

    خوب بیایم الان کلاس dog را تکمیل کنیم:

    73.jpg


    فقط سگ‌ها می‌توانند پارس کنند بنا بر این زیر کلاس این متد را دارد. سوپر کلاس هرگز به این متد دسترسی ندارد.

    در واقع متد bark فقط برای کلاس dog هست

    خوب الان کلاس cat رو هم تکمیل کنیم:

    این متد فقط در کلاس گربه وجود دارد. سگ‌ها چیزی از این متد نمی‌دانند و همچنین سوپر کلاس هم چیزی از این متد نمی داند. و این همان چیزی است که ارث بری در جاوا را چنین قدرتمند می کند: توانایی تعریف متد ها و متغیر های مشترک در یک مکان و استفاده از آن‌ها دوباره و دوباره. جاوا اشیاء خودش را به شکل سلسله مراتبی می‌سازد و چه زیباست از این فایده استفاده کنیم. حتی دلایل بیشتری برای قدرتمندی ارث بری در جاوا وجود دارد اما ما به آن دلایل در این درس نامه نمی پردازیم.

    در واقع کلاس‌های فرزند در ویژگی‌ها و توانایی‌های پدر مشترک هستند ولی هر کدام می‌تواندد ویژگی‌های خودشان را داشته باشند و حتی می‌توانند این توانایی یا ويژگی‌های ارث بـرده شده را برای خود تغییر داده و استفاده کنند.

    74.jpg


    خوب @Override در واقع بیان گر این هست که شما متدی با همین اما در کلاس پدر دارین و فرزند داره این متد رو بازنویسی میکند

    که این علامت بازگو کننده همین مطلب هست

    خوب چند نکته‌ای در ارث بری وجود دارد که شاید فهمیدنشون لازم باشه. فرض کنید کلاس پدر یه متغییر به نام a داشته باشد. همچنین کلاس فرزند نیز یک متغییر همنام با a داشته باشد که متفاوت باشند! چطوری این موضوع رو باید در جاوا حل کرد؟

    75.jpg


    76.jpg


    خوب اگر در کلاس فرزند بخواهیم هر دو متغییر را مقدار دهی کنیم چطوری باید تمایز ایجاد کنیم؟

    خوب از دو کلمه کلیدی this برای اشاره به متغییر در کلاس فرزند و کلمه کلیدی super برای متغییر کلاس پدر استفاده میکنیم.

    77.jpg


    همچنین هم باید دقت شود اگر کلاس پدر دارای سازنده باشد، حتما کلاس‌های فرزند موظف هستند که این سازنده را مقدار دهی کنند وگرنه اجازه ارث‌بری نخواهند داشت. که فرخوانی سازنده کلاس پدر با کلمه کلیدی super() انجام می‌شود و همچنین الزامی وجود دارد بر اینکه مقدار دهی سازنده پدر همیشه در خط اول سازنده فرزند باشد!



    Read
     

    *بانو بهار*

    کاربر نگاه دانلود
    کاربر نگاه دانلود
    عضویت
    2016/08/15
    ارسالی ها
    3,937
    امتیاز واکنش
    10,965
    امتیاز
    804
    محل سکونت
    میان شکوفه‌ها
    این جلسه در مورد Collection ها یا مجموعه ها صحبت می‌کنیم. به طور کلی مجموعه‌ها در جاوا به عنوان یه نوع ساختمان داده تعریف می‌شند که میتونند انواع داده رو در خودشون ذخیره کنند. که اگه فرصت بشه جلسات آینده نحوه ساخت این نوع کلاس‌ها و ساختمان داده ها که انواع داده ها را می‌تونند ذخیره کنند و پردازش کنند صحبت خواهیم کرد.

    اما بریم سراغ تعریف ساختمان داده،

    سازمان‌دادنِ داده‌ها به یک طریق خاص و بر پایهٔ مدل منطقی یا ریاضی که به منظور استفادهٔ بهینه از داده‌ها صورت می‌گیرد را یک ساختارِ داده‌ها گویند. ساختارهای داده‌ها انواع گوناگونی دارند که هر کدام مناسب برنامه‌های مختلفی هستند.

    شماری از ساختارهای داده‌های پرکاربرد:

    آرایه (Array)

    صف (Queue)

    پشته (Stack)

    لیست پیوندی (Linked list)

    گراف (Graph)

    درخت (Tree)

    جدول درهم‌سازی (Hash table)

    در جاوا علاوه بر ساختمان داده های بالا ساختمان داده های دیگری هم وجود دارد

    همه این موارد به خاطر اینکه به نوع داده محدویدتی ندارند و یه نوع ساختمان داده هستند جز Collection ها قرار می‌گیرند.

    خوب منظورمون از اینکه به نوع داده محدود نیستن یعنی چی؟ منظور اینکه شبیه به آرایه ها که شما میتونید آرایه‌ای از هر چیز بسازین، میتونیم از Collection از هر نوع داده‌ای بسازیم بدون توجه به نوع داده!

    خوب بریم سراغ ساده ترین کالکشن یا همان List. یک لیست چیزی به جز یک آرایه نیست که دارای طول متغییر هست. در واقع یک آرایه پویا هست که طول آن در حال تغییر هست.

    �(وارد جزییات نحوه پیاده سازی آن نمیشم، با اینکه برای اینکه به درستی بتونیم برنامه‌هامون رو بهینه کنیم نیاز به این داریم که نحوه پیاده سازی همه این ساختمان داده ها را بدونیم تا بدونیم کدوم رو در کجا استفاده کنیم.)

    در جاوا یک لیست به صورت List به این صورت نوشته می‌شود:



    List listName = new ArrayList<>();
    مثلا:

    List list1 = new ArrayList<>();
    List list2 = new ArrayList<>();
    List list3 = new ArrayList<>();
    همان طور که میبیند ما میتونیم انواع لیست‌ از جنس‌های مختلف پیاده سازی کنیم. فقط کافی هست نوع داده خودمون رو مشخص کنیم.

    در واقع مشخص می‌کنیم type هر کدوم از خونه‌های این لیست یا آرایه پویا از چه جنـ*ـسی باشد:

    list1.add(“hello”);
    list2.add(1000);
    متد add در واقع عنصر شما را در انتهای آرایه قرار می‌دهد.

    همچنین شما میتونید یه عنصر را در یک خانه مشخص اضافه کنید:

    list1.add(3, “hi”);
    با متد size() شما میتونید هر لحظه اندازه لیست خودتون رو بدونید:

    list1.size();
    و سایر متدها که از گفتنشون صرفه نظر میکنیم. ولی استفاده از اون‌ها لازم میشه

    حتما بررسی کنید...

    خوب بریم سراغ مطلب اصلی بحث. ما میتونیم این لیست پویا را به صورت‌های مختلف پیاده سازی‌کنیم. توجه کنید نوع عملکرد یعنی ورودی و خروجی ها یکسان هستند ولی نحوه ذخیره سازی پیاده‌سازی‌های مختلف متفاوت هست:

    List list1 = new ArrayList<>();
    List list2 = new LinkedList<>();
    شما در بالا با دو نوع پیاده سازی مختلف لیست ها آشنا شدین. باز تاکیید میکنم همه توابع شبیه add یا size یا get برای هر دو نوع پیاده سازی خروجی های یکسانی دارد ولی نحوه پیاده سازی و نحوه ذخیره سازی اون‌ها در داخل حافظه متفاوت هست.

    بنابراین ما باید با توجه به ساختار کد و نیاز تشخیص بدیم که از کدوم یک از پیاده سازی ها استفاده کنیم. همچنین شاید لازم باشه خودمان یه نوع پیاده سازی خاصی از لیست داشته باشیم! (که بخاطر پیچیده شدن بحث صرفه نظر می‌کنیم ولی اگه سوالی بود انتهای جلسه بپرسین)

    فقط این نکته رو یادآوری کنم پیاده سازی به روش ArrayList از یک آرایه معمولی استفاده شده است ولی برای پیاده سازی LinkedList از اشاره‌گرها استفاده شده است.

    کالکشن بعدی که در مورد اون صحبت می‌کنیم Set هست. دقیقا این کالکشن تعریف ریاضی مجموعه ها را دارند. در واقع مجموعه‌ای از داده‌ها که نمی‌توانند عضو تکراری داشته باشند و همچنین موقعیت عناصر اهمیتی ندارد.

    Set set = new HashSet<>


    Read more:
     

    *بانو بهار*

    کاربر نگاه دانلود
    کاربر نگاه دانلود
    عضویت
    2016/08/15
    ارسالی ها
    3,937
    امتیاز واکنش
    10,965
    امتیاز
    804
    محل سکونت
    میان شکوفه‌ها
    کتاب اول رو روی میز میگذاریم. کتاب دوم رو روی کتاب اول. کتاب سوم رو هم روی کتاب دوم میگذاریم.

    خوب الان اگه بخواهیم کتاب اول رو برداریم، مجبوریم که اول کتاب که در بالای همه هست (کتاب سوم) رو ابتدا برداریم و کنار بگذاریم، بعد کتاب دوم و در نهایت به کتاب اول برسیم.



    در واقع این ساختمان داده شبیه یه آرایه هست که داده‌ای که اول می‌آید همیشه آخر خارج می‌شود و عنصری که جدید آمده است زودتر از سایرین خارج می‌شود!

    خوب این ساختمان داده دو متد معروف داد به نام‌های push و pop.

    متد push یک عنصر دریافت می‌کند و آن را داخل ساختمان قرار داده و متد pop به نحوی که بالا گفتم عنصر را خارج می‌کند.

    در جاوا شما می‌تونید به این صورت از استک استفاده کنید:

    91.jpg


    خوب الان قصد داریم خودمون این ساختمان داده رو پیدا سازی کنیم.



    فرض کنید هدف ساختن یک ساختمان داده از جنس int هستیم.

    پس اجازه بدین دست به کار بشیم

    خوب برای پیاده سازی این ساختمان داده نیاز به یک آرایه از جنس int داریم. و همیشه باید بدونیم در هر لحظه چه تعداد عنصر داخل این آرایه هست. پس کد ما به این صورت میشه:

    92.jpg


    خوب شاید سوال براتون پیش بیاد که چرا top با مقدار اولیه -۱ مقدار دهی شده؟

    جواب این سوال برمیگرده به نحوه پیاده سازی متد push و pop که پیاده سازی میکنیم. ولی در حالت کلی وقتی هیچ عنصری داخل ارایه ما نباشه مقدار top برابر است با -۱ چون ارایه ما از ۰ شروع میشن.

    خوب تابع push به این صورت میشه:

    public void push(int value){
    top++;
    array[top] = value;
    }
    public void push(int value){
    top++;
    array[top] = value;
    }


    که مشخصا معلوم هست برای اضافه کردن ابتدا یک واحد به top زیاد می‌کنیم و بعد� مقدار value یا همان مقداری که قرار اضافه شود را به آرایه اضافه میکنیم.



    به همین صورت متد pop:

    public int pop(){
    int value = array[top];
    top--;
    return value;
    }


    ابتدا مقدار خانه که top به آن اشاره میکند رو نگه داشته. top را کم میکنیم و مقدار آن رو return میکنیم.



    و یک سری متد دیگه… . خروجی به این صورت میشه:

    93.jpg




    بدون اینکه اون رو حذف کنه!

    متد peek شبیه pop هست با این تفاوت که همیشه اخرین عنصر رو برمیگردونه

    متد isEmpty هم خالی بودن ساختمان داده رو بررسی می‌کند

    و isFull پر بودن ساختمان داده رو

    خوب برای استفاده به این صورت عمل میکنیم:

    public static void main(String[] args){
    MyStack theStack = new MyStack(10);
    theStack.push(10);
    theStack.push(20);
    theStack.push(30);
    theStack.push(40);
    theStack.push(50);
    while (!theStack.isEmpty());
    long value = theStack.pop();
    System.out.print(value);
    System.out.print(" ");
    }
    System.out.println("");
    }


    خروجی کد هم به این صورت خواهد بود:



    50 40 30 20 10
    دقیقا برعکس چیزی که وارد کردیم. یعنی اولین عنصر که وارد شدهُ اخرین عنصر هست که چاپ می‌شود.

    خوب تا اینجای بحث خیلی ساده بود و چیز خیلی خاصی گفته نشد. ولی سوالی که پیش میاد این هست که اگه ما بخواهیم یک استک از جنس String داشته باشیم چی؟ یا یک استک از جنس Student و یا از هر جنـ*ـسی!!

    ساده ترین راه حل این هست که به ازای هرکدوم از type های که نیاز داریم یک کلاس جدا بنویسیم!! راه حل ساده ولی بدترین روش ممکن!!!

    راه حل دوم اینکه نوع آرایه استک رو از جنس Object بگیریم. خوب اینجوری هر نوع عنصری رو میشه باهم داخل آرایه ریخت. در واقع یک آرایه ساخته میشه از انواع type ها.

    خوب مدیریت این نوع آرایه ها به شدت سخت هست چون هر خانه‌ اون میتونه هر نوع داده‌ای باشه و همچنین نیاز به تبدیل کردن و cast کردن هستیم!! خوب پس این روش هم مناسب نیست.

    چاره کار استفاده از مفهومی در جاوا هست به نام Genericها. در واقع جنریک‌ها این قابلیت را به ما میدن که بدون در نظر گرفتن نوع type برای آن ها کلاس بسازیم. مثلا کلاس استک



    خوب وقتی کلاس استک رو به صورت Generic بنوسیسم. یکبار می‌نویسیم و برای انواع داده‌ها ازش استفاده میکنیم! واقعا عالی هست مگه نه؟

    البته مفهوم جنریک خیلی گسترده هست و نکات ریزی داره در استفاده ولی ما به صورت کلی صحبت می‌کنیم و به جزییات نمی‌پردازیم.

    خوب قبل از شروع یک یادآوری از کلاس List بکنیم. یادتون هست چطور یک لیست در جاوا میساختیم؟

    List list = new ArrayList<>();
    List list = new ArrayList<>();


    ما اینجا یک لیست از جنس String ساخته‌ایم و اگه بخواهیم از جنس Integer بسازیم به این صورت:



    List list = new ArrayList< > ();
    شما میتونید انواع type ها رو برای این کلاس لیست بنویسید. در واقع کالکشن لیست به صورت جنریک پیاده‌سازی شده‌اند. یعنی در واقع هر نوع داده‌ای رو میتونه قبول کند. فقط کافیه نوع داده خودمون رو داخل <> قرار بدیم تا لیست ما از جنس آن type بشه.

    در واقع همه کالکشن‌ها در جاوا به صورت جنریک پیاده سازی شده‌اند و هرکجا علامت <> رو دیدن در واقع یاد جنریک‌ها بیوفتین!

    این این جلسه به صورت مختصر توضیح میدیم و جلسه بعدی با مثال بیشتر در موردش صحبت میکنیم. این جلسه فقط با ظاهر جنریک آشنا بشیم و توضیحاتش برای جلسه بعدی باشد.



    کلاس استک ما به صورت جنریک به این صورت خواهد بود:

    94.jpg


    در اینجا ما در کنار اسم کلاس type به نام T تعریف کردیم که واقعا وجود ندارد و یک تایپ به صورت جنرال هست. یعنی هر تایپی میتونه باشه و برای ما مهم نیست.

    دقت کنید نوع آرایه و ورودی و خروجی متدهای pop و push تبدیل به همین نوع T شده اند.

    اجازه بدین در جلسه بعدی با جزییات بیشتری در موردش حرف بزنیآ
     

    *بانو بهار*

    کاربر نگاه دانلود
    کاربر نگاه دانلود
    عضویت
    2016/08/15
    ارسالی ها
    3,937
    امتیاز واکنش
    10,965
    امتیاز
    804
    محل سکونت
    میان شکوفه‌ها
    جلسه قبلی با هم ساختمان داده استک یا پشته را پیاده سازی کردیم ولی همون طور که دیدم برای انواع type ها لازم هست یه کلاس جداگانه بسازیم. بعد گفتیم ما میتونیم جوری یه کلاس و ساختمان داده رو بسازیم که محدود به نوع داده نباشد.

    در واقع در پیاده سازی یه ساختمان داده نباید به نوع داده محدود باشد. چون هر نوع داده ای رو باید قبول کند و بتونه ذخیره کند.

    خوب توی این جلسه میخایم ببنیم چطور میتونیم کلاس MyStack جلسه پیش رو به این صورت تبدیل کنیم که به نوع داده محدود نباشد. به این نوع کلاس ها که به نوع داده محدودیتی نداشته باشند Generic گفته میشه.

    همه ساختمان داده های پیشفرض جاوا به صورت جنریک پیاده سازی شده‌اند.

    خوب کلاس MyStack رو اگه بخواهیم به صورت جنریک بنویسم به این صورت می‌شود. که خط به خط توضیح داده میشه:

    101.jpg


    خوب در خط ۴ در تعریف کلاس بعد از اسم کلاس ما <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 هست. و این ورودی را در آرایه قرار می‌دهد.

    به همین صورت سایر توابع دیگر…

    خوب ببینیم طریقه استفاده از این کلاس به چه صورتی هست:

    102.jpg


    خوب همون طور که میبیند من نوع ورودی ساختمان دادم رو String گذاشتم و همان طور که میبیند ورودی و خروجی توابع push� و pop هم String شدند.

    خوب اجازه بدین یکبار دیگه هم تست کنیم:

    103.jpg




    Read
     

    برخی موضوعات مشابه

    بالا