آموزش قدم به قدم جاوا – قسمت هفدهم – بخش دوم

فراخوانی سازنده‌ها در وراثت

یکی از نکاتی که هنگام ارث‌بری از کلاس‌ها باید به آن توجه داشت، سازنده کلاس پدر (Superclass) است. به کلاس Employee که در قسمت قبل آن را نوشتیم یک سازنده اضافه می‌کنیم:

در این سازنده یک دستور چاپ وجود دارد که عبارت “سازنده کلاس Employee فراخوانی شد را چاپ می‌کند و در خطوط بعدی آن به فیلدهای name و salary مقداردهی شده است (با انتساب مقادیر پارامترهای سازنده به فیلدهای کلاس).

حال به کلاس Accountant یک سازنده با یک پارامتر اضافه می‌کنیم:

همانطور که دیدید در این سازنده علاوه بر چاپ عبارت “سازنده کلاس Accountant فراخوانی شد مقدار پارامتر workingHours را نیز به فیلد workingHours کلاس خود نسبت دادیم.

همه چیز تا الان درست به نظر می‌آید اما یک سوال مهم وجود دارد: می‌دانیم که کلاس Accountant از کلاس Employee ارث‌بری دارد و به همین دلیل اگر شیئی از کلاس Accountant ایجاد کنیم اعضای کلاس Employee نیز در آن شی وجود دارند. اگر به شکل زیر شیئی از کلاس Accountant ایجاد کنیم:

به سازنده کلاس Accountant مقدار 8 را دادیم تا آن را به فیلد workingHours نسبت دهد. اما تکلیف فیلدهای کلاس Employee که حالا در این شی وجود دارند چه می‌شود؟ چگونه باید به فیلدهایی که کلاس Accountant از کلاس Employee به ارث‌برده مقدار دهیم؟

همانطور که می‌دانید قسمتی از کلاس Accountant در کلاس Employee قرار دارد (اعضای تعریف شده در کلاس Employee) و قسمتی از آن هم در خود کلاس Accountant قرار دارد (فیلد workingHours) بنابراین می‌گوییم که سازنده کلاس Employee مسئول تولید و مقداردهی به آن قسمتی است که در کلاس Employee قرار دارد و سازنده کلاس Accountant نیز مسئول مقداردهی به قسمتی که در کلاس Accountant است لذا برای ایجاد یک شی از کلاس Accountant باید هر دو قسمت کلاس ساخته شود.

پس باید در سازنده کلاس Accountant سازنده کلاس Employee را فراخوانی کنیم تا هنگام ایجاد شی از کلاس Accountant اعضای موجود در Employee نیز مقدار دهی شوند.

سازنده کلاس Accountant را تغییر می‌دهیم و دو پارامتر به آن اضافه می‌کنیم. سپس باید سازنده کلاس پدر یعنی Employee را فراخوانی کنیم که این کار را با super انجام می‌دهیم:

همانطور که در کد معلوم است با استفاده از عبارت super سازنده کلاس Employee را فراخوانی کرده و پارامترهای name و salary را به آن دادیم. البته در این سازنده می‌توان به جای name و salary هر اسمی نوشت اما باید به ترتیب قرار دادن آن در super توجه داشت.

اگر شیئی از کلاس Accountant ایجاد کنید نتیجه زیر را در پنجره کنسول خواهید دید:

Employee Constructor Called.

Accountant Constructor Called.

از این خروجی متوجه می‌شویم که هنگام ایجاد شی از کلاس Accountant قبل از فراخوانی سازنده کلاس Accountant سازنده کلاس پدر آن یعنی Employee فراخوانی شده است.

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

سلسله مراتب وراثت

در کلاس‌های Accountant و Employee سلسله مراتب وراثت به صورت زیر است:

Employee -> Accountant

یعنی در این سلسله مراتب فقط دو کلاس وجود دارد که کلاس Accountant از Employee ارث‌بری دارد. اما این سلسله مراتب فقط محدود به دو کلاس نیست بلکه این زنجیره می‌تواند به هر تعدادی باشد. مثلا می‌توانیم کلاسی به نام Person (شخص) ایجاد کنیم که کلاس Employee از آن ارث‌بری داشته باشد:

Person -> Employee -> Accountant

به این ترتیب کلاس Accountant هم اعضای کلاس Employee و هم اعضای کلاس Person را به ارث خواهد برد. رابطه Is-A به این صورت خواهد شد: هر حسابدار یک کارمند است و هر کارمند یک شخص است.

Override کردن متدها

اگر در یک رابطه وراثتی متدی در کلاس فرزند وجود داشته باشد و متدی با همان امضا و نوع داده بازگشتی (قبلا گفتیم که امضای متد شامل نام و تعداد و نوع پارامترهای آن متد است) در کلاس پدر آن نیز وجود داشته باشد می‌گوییم که کلاس فرزند آن متد را Override کرده است.

مثال:

کلاسی به نام Person داریم:

کلاس دیگری به نام FrenchPerson داریم که از Person ارث بری دارد:

اگر شیئی از کلاس FrenchPerson ایجاد کنیم و متد sayHello آن را فراخوانی کنیم عبارت Hello در کنسول چاپ خواهد شد. اما یک فرد فرانسوی این‌گونه سلام نمی‌کند. می‌خواهیم متد sayHello در کلاس Person را در کلاس فرزند آن Override کنیم:

حال اگر از شی ساخته شده از کلاس FrenchPerson متد sayHello را فراخوانی کنید دیگر عبارت Hello چاپ نخواهد شد چون ما آن متد را Override کردیم و بنابراین عبارت Bonjour چاپ می‌شود.

اما گاهی اوقات لازم است تا در یک متد Override شده متد کلاس پدر آن هم فراخوانی شود. می‌توان با super به صورت زیر این کار را انجام داد:

حال اگر متد sayHello از کلاس FrenchPerson را فراخوانی کنید هر دو عبارت Hello و Bonjour چاپ خواهد شد.

نکته: فراخوانی متد کلاس پدر با عبارت super می‌تواند در هرجای متد باشد و الزاما نیازی به استفاده از super در خط اول متد نیست.

نکته: اگر متدی که از کلاس پدر Override کردید پارامتر داشته باشد آنگاه هنگام فراخوانی آن با super باید پارامترهای مورد نیازش را هم به آن بدهید. به عنوان مثال اگر متد sayHello یک پارامتر رشته‌ای به نام name دریافت می‌کرد به صورت زیر عمل می‌کردیم:

super

از super برای فراخوانی سازنده کلاس پدر استفاده کردیم اما super کاربردهای دیگری نیز دارد. یکی از کاربردهای آن دسترسی به اعضای کلاس پدر است.

مثال: کلاسی به نام A با یک فیلد به نام i داریم:

کلاس دیگری به نام B داریم که از A ارث‌بری دارد. در این کلاس هم فیلدی به نام i تعریف شده است:

در متد setNumber می‌بینید که مقدار 20 را به i نسبت دادیم. اما کدام i ؟ کلاس B هم فیلد i کلاس A را به ارث برده و هم خود فیلدی به نام i دارد. فیلد i ای که در کلاس B وجود دارد فیلد i ارث برده از کلاس A را مخفی (Shadow) می‌کند بنابراین برای دسترسی به فیلدی از کلاس پدر در کلاس فرزند می‌توانیم از super استفاده کنیم. اگر کد متد setNumber را به صورت زیر تغییر دهیم:

آنگاه مقدار i به فیلد i کلاس A نسبت داده می‌شود.

نکته: فقط در صورتی برای دسترسی به فیلدهای کلاس پدر به super نیاز داریم که فیلدی در کلاس فرزند با همان نام وجود داشته باشد و فیلد کلاس پدر خود را مخفی کرده باشد. در مثال بالا اگر در کلاس B فیلدی به نام i وجود نداشت می‌توانستیم بدون استفاده از عبارت super و به صورت مستقیم به فیلد i موجود در کلاس A دسترسی داشته باشیم.

مصطفی نصیری

دانشجوی نرم افزار هستم و علاقه شدیدی به برنامه نویسی مخصوصا با زبان جاوا دارم! در حال حاضر تمرکزم روی اندرویده. دوست دارم چیزایی که یاد میگیرم رو با بقیه به اشتراک بگذارم :)

همچنین ممکن است دوست داشته باشید ...

۷ واکنش

  1. user گفت:

    آموزش‌ها به‌نظرم خیلی حرفه‌ای و با جرئیات و نکات اصولی همراهه. مرسی و خسته نباشی.

  2. iman 313 گفت:

    ایول شما عالی هستین ولی ایکاش بازم اموزش های اینطوری از جاوا بزارید مثلا تکنیک هارو اموزش بدین یا به GUI بپردازین

    • مصطفی نصیری گفت:

      خواهش می کنم شما لطف دارید. قصد دارم در آینده یک سری آموزش های نهایتا ۲-۳ قسمتی منتشر کنم اما نوشتن آموزش های قدم به قدم و طولانی به دلیل کمبود وقت در توانم نیست.

      • iman گفت:

        ولی اگه یه اموزش کامل مثل جاوا در موزد git هم بزارید خیلی باحالید !
        من که تا الان یه آموزش فارسی درست حسابی در مورد git پیدا نکردم

  3. iman گفت:

    سلام پیشنهاد میکنم که در قسمت constructor این نکته رو هم اضافه کنید که () super (یا فراخانی کانستراکتور کلاس پدر ) باید حتما در خط اول باشد . مرسی

  4. Ahmad-T گفت:

    خیلی ممنون بابت زحماتتون. خوشحالم که با شما آشنا شدم.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *