پس از آشنایی با مفهوم وراثت در زبان برنامهنویسی جاوا در آموزش گذشته، در این آموزش قصد داریم تا سناریویی همچون مثال مطرحشده در آموزش قبل را مد نظر قرار داده و آن را پیادهسازی نماییم که برای این منظور پروژهای تحت عنوان InheritanceProject ایجاد کرده و داخل آن سه کلاس مجزا تحت عناوین Grandfather
،Father
و Son
به ترتیب برای تعریف خصوصیات پدربزرگ، پدر و پسر ایجاد میکنیم (نکتۀ قابلتوجه در ارتباط با این کلاسها این است که برای ساخت آنها نیازی به زدن تیک گزینۀ public static void main نداریم چرا که کلاسهای مذکور به منزلۀ نقطه شروع برنامه نمیباشند.)
در ادامه، کلاسی تحت عنوان ActionClass
ایجاد کرده و در زمان ساخت آن نیز تیک گزینۀ public static void main را میزنیم و بدین ترتیب کلاس ActionClass
را به عنوان کلاسی برای نقطۀ شروع اجرای برنامۀ خود قرار میدهیم. حال برای شروع کدنویسی پروژه از کلاس Grandfather
شروع میکنیم که پس از باز کردن فایل این کلاس کدی به صورت زیر خواهیم داشت:
public class Grandfather {
}
اکنون در کلاس Grandfather
به منظور ذخیرهسازی خصوصیات پدربزرگ، یکسری متد تعریف میکنیم و برای این منظور کلاس فوق را به صورت زیر تکمیل مینماییم:
public class Grandfather {
public void showGrandfatherHeight() {
String height = "Short";
System.out.println(height);
}
public void showGrandfatherSkinColor() {
String skinColor = "Bright";
System.out.println(skinColor);
}
public void showGrandfatherBaldness() {
String baldness = "Bald";
System.out.println(baldness);
}
public void showGrandfatherBehavior() {
String behavior = "Angry";
System.out.println(behavior);
}
public void showGrandfatherCreativity() {
String creativity = "Very Creative";
System.out.println(creativity);
}
public void showGrandfatherActivity() {
String activity = "Active";
System.out.println(activity);
}
public void showGrandfatherNationality() {
String nationality = "Iranian";
System.out.println(nationality);
}
}
همانطور که مشاهده میکنیم، سطوح دسترسی تمامی متدهای کلاس را public
در نظر گرفتهایم چرا که میخواهیم از طریق سایر کلاسها در دسترس باشند (در آموزش آشنایی با انواع سطوح دسترسی در زبان برنامهنویسی جاوا سطوح مختلف دسترسی را در این زبان مورد بررسی قرار دادهايم.)
در كد فوق، ابتدا متدی تحت عنوان ()showGrandfatherHeight
تعریف کردهایم و دستورات داخلی آن را به منظور نمایش قد پدربزرگ بدین صورت پیادهسازی کردهایم که در آن گفتهایم در صورت فراخوانی متد مذکور، آبجکتی از روی کلاس String
تحت عنوان height
ساخته شده و استرینگ «Short» بدان منتسب شود و در ادامه height
به عنوان آرگومان ورودی به متد ()println
پاس داده شده تا استرینگ اختصاصیافته به این متغیر در کنسول چاپ گردد.
در ادامه، متدی تحت عنوان ()showGrandfatherSkinColor
تعریف کردهایم که دستورات داخلی آن به منظور نمایش رنگ پوست پدربزرگ بدین صورت تعریف شدهاند که در صورت فراخوانی متد مذکور، آبجکتی به نام skinColor
از روی کلاس String
ساخته شده و استرینگ «Bright» به آن اختصاص داده میشود و در ادامه مشابه متد قبل، استرینگ مذکور در کنسول چاپ میگردد.
متد سوم نیز تحت عنوان ()showGrandfatherBaldness
تعریف شده و دستورات داخلی آن به منظور نشان دادن طاسی پدربزرگ بدین صورت پیادهسازی شدهاند که در صورت فراخونی این متد، آبجکتی به نام baldness
از روی کلاس String
ساخته شده و استرینگ «Bald» بدان منتسب شده و در ادامه مشابه متدهای پیشین، استرینگ مذکور در کنسول نمایش داده میشود.
در ادامه، متد دیگری تحت عنوان ()showGrandfatherBehavior
تعریف کردهایم که در صورت فراخوانی، آبجکتی به نام behavior
از روی کلاس String
ساخته شده و استرینگ «Angry» بدان منتسب میشود و در ادامه با بهکارگیری متد ()println
مقدار منتسب به آن در کنسول چاپ میگردد.
همچنین متد دیگری تحت عنوان ()showGrandfatherCreativity
داریم که به منظور نمایش میزان خلاقیت پدربزرگ تعریف شده و در صورت فراخوانی متد مذکور، آبجکتی به نام creativity
از روی کلاس String
ساخته شده و استرینگ «Very Creative» بدان منتسب میگردد و در ادامه مشابه متدهای پیشین، مقدار اختصاصیافته به creativity
در کنسول چاپ میشود.
در ادامه، به منظور نمایش میزان فعالیت پدربزرگ، متد دیگری به نام ()showGrandfatherActivity
تعریف کرده و دستورات داخلی آن را بدین صورت تعریف کردهایم تا در صورت فراخوانی، آبجکتی به نام Activity
از روی کلاس String
ساخته و استرینگ «Active» را بدان منتسب کرده و در ادامه مشابه آنچه در متدهای پیشین توضیح دادیم، استرینگ مذکور را در کنسول چاپ میکند.
در نهایت متد هفتم تحت عنوان ()showGrandfatherNationality
را تعریف کردهایم که به منظور نمایش ملیت پدربزرگ به کار گرفته شده و در حین فراخوانی، ابتدا آبجکتی از روی کلاس String
تحت عنوان nationality
ساخته و استرینگ «Iranian» را بدان اختصاص داده و در ادامه با فراخوانی متد ()println
استرینگ مذکور را در کنسول چاپ مینماید.
اکنون به منظور تست برنامۀ فوق، آبجکتی از روی کلاس Grandfather
در کلاس ActionClass
ایجاد کرده سپس متدهای تعریفشده در کلاس Grandfather
را روی آبجکت ساختهشده فراخوانی میکنیم که برای این منظور کلاس ActionClass
را باز کرده و کدی به صورت زیر داخل آن مینویسیم:
public class ActionClass {
public static void main(String[] args) {
Grandfather grandfatherObject = new Grandfather();
grandfatherObject.showGrandfatherHeight();
grandfatherObject.showGrandfatherSkinColor();
grandfatherObject.showGrandfatherBaldness();
grandfatherObject.showGrandfatherBehavior();
grandfatherObject.showGrandfatherCreativity();
grandfatherObject.showGrandfatherActivity();
grandfatherObject.showGrandfatherNationality();
}
}
همانطور که در کد فوق ملاحظه میکنیم، پس از ساخت آبجکتی از روی کلاس Grandfather
تحت عنوان grandfatherObject
میتوانیم متدهای تعریفشده در این کلاس را روی آبجکت مذکور فراخوانی نماییم. حال پس از اجرای برنامۀ فوق در خروجی خواهیم داشت:
Short
Bright
Bald
Angry
Very Creative
Active
Iranian
همانطور که میبینیم، کلیۀ اتریبیوتهای تعریفشده برای کلاس Grandfather
در کنسول نمایش داده میشوند. اکنون به تعریف ویژگیهای کلاس Father
میپردازیم و برای این منظور فایل کلاس مذکور را باز کرده و در ابتدا کد آن را به صورت زیر تغییر میدهیم:
public class Father extends Grandfather {
}
در کد فوق، کلیدواژۀ extends
بدین منظور به کار گرفته شده است تا کلاس Father
خصوصیات خود را از کلاس Grandfather
ارثبری کند. به عبارت دیگر، از این پس کلاس Father
کلیهٔ ویژگیهای کلاس Grandfather
را دارا است اما همانطور که در آموزش قبل بیان کردیم، برخی خصوصیات پدر با پدربزرگ متفاوت میباشد که از آن جمله میتوان به خوشاخلاق بودن پدر و همچنین خلاقیت کمتر وی اشاره کرد و از همین روی نیاز داریم تا برخی از اتریبیوتهایی که کلاس Father
از کلاس Grandfather
به ارث برده است را به اصطلاح Override نماییم (همچنین در آموزش قبل بدین موضوع اشاره کردیم که پدر ویژگیهای دیگری همچون تحصیلات لیسانس و میزان مطالعۀ زیاد دارا است که به علاوۀ سایر خصوصیاتی میباشند که از پدربزرگ به ارث برده است.)
به منظور حل مسائلی از این دست در زبان برنامهنویسی جاوا، از مفهوم Override استفاده میکنیم. به عبارت دیگر، زمانی که بخواهیم که یک Subclass برخی از ویژگیهای Superclass را به ارث نبرد، میباید خصوصیات مد نظر را Override یا «رونویسی» نماییم که برای این منظور، کلاس Father
را به شکل زیر اُورراید میکنیم:
public class Father extends Grandfather {
@Override
public void showGrandfatherBehavior() {
String behavior = "Well-behaved";
System.out.println(behavior);
}
@Override
public void showGrandfatherCreativity() {
String creativity = "Creative";
System.out.println(creativity);
}
}
در حقیقت، اُورراید کردن بدین شکل صورت میگیرد که پیش از نوشتن نام متد مربوطه، دستور Override@
را نوشته سپس تغییرات مد نظر را در اتریبیوتهای آن متد اِعمال مینماییم. همانطور که در کد فوق مشاهده میکنیم، از میان تمامی متدهای موجود در کلاس Grandfather
تنها دو متدی را نوشتهایم که نیاز به اُورراید شدن داشتند و در ادامه اتریبیوتهای آنها را تغییر دادهایم. در واقع، مقدار منتسب به اتریبیوت behavior
را معادل با استرینگ «Well-behaved» در نظر گرفته و همچنین مقدار اتریبیوت creativity
را معادلِ استرینگ «Creative» قرار دادهايم.
اکنون خصوصياتی را به کلاس Father
اضافه میکنیم که پدربزرگ آنها را نداشته و خصوصیاتی منحصربهفرد برای پدر میباشند که این خصوصیات عبارتند از تحصیلات لیسانس و میزان مطالعهٔ زیاد پدر که به منظور اضافه کردن آنها به روش زیر عمل میکنیم:
public class Father extends Grandfather {
@Override
public void showGrandfatherBehavior() {
String behavior = "Well-behaved";
System.out.println(behavior);
}
@Override
public void showGrandfatherCreativity() {
String creativity = "Creative";
System.out.println(creativity);
}
public void showFatherEducation() {
String education = "BA";
System.out.println(education);
}
public void showFatherStudyTime() {
String studyTime = "Much";
System.out.println(studyTime);
}
}
همانطور که ملاحظه میکنیم، متد جدیدی تحت عنوان ()showFatherEducation
تعریف کرده و داخل آن گفتهایم در صورت فراخوانی آن، آبجکتی به نام education
از روی کلاس String
ساخته شده و استرینگ «BA» بدان منتسب گردد و در ادامه متغیر education
به عنوان آرگومان ورودی به متد ()println
پاس داده شده و بدین ترتیب استرینگ اختصاصیافته به education
در کنسول نمایش داده میشود.
سپس متدی دیگری تحت عنوان ()showFatherStudyTime
ایجاد کرده و آبجکتی به نام studyTime
از روی کلاس String
ساخته و استرینگ «Much» را بدان منتسب میکنیم تا در صورت فراخوانی متد مذکور، استرینگ مربوطه به عنوان ورودی به متد ()println
پاس داده شده و در کنسول چاپ گردد (دو متد ()showFatherStudyTime
و ()showFatherEducation
صرفاً مخصوص کلاس Father
بوده و سایر کلاسها به متدهای مذکور دسترسی ندارند.)
حال برای تست عملکرد کلاس Father
آبجکتی از روی کلاس مذکور در کلاس ActionClass
ساخته و متدهای تعریفشده در کلاس Father
را روی آبجکت مربوطه فراخوانی مینماییم که برای این منظور میتوانیم به روش زیر عمل کنیم:
public class ActionClass {
public static void main(String[] args) {
// Grandfather grandfatherObject = new Grandfather();
// grandfatherObject.showGrandfatherHeight();
// grandfatherObject.showGrandfatherSkinColor();
// grandfatherObject.showGrandfatherBaldness();
// grandfatherObject.showGrandfatherBehavior();
// grandfatherObject.showGrandfatherCreativity();
// grandfatherObject.showGrandfatherActivity();
// grandfatherObject.showGrandfatherNationality();
Father fatherObject = new Father();
fatherObject.showGrandfatherHeight();
fatherObject.showGrandfatherSkinColor();
fatherObject.showGrandfatherBaldness();
fatherObject.showGrandfatherBehavior();
fatherObject.showGrandfatherCreativity();
fatherObject.showGrandfatherActivity();
fatherObject.showGrandfatherNationality();
fatherObject.showFatherEducation();
fatherObject.showFatherStudyTime();
}
}
کدهای مربوط به کلاس Grandfather
را به منظور جلوگیری از شلوغ شدن خروجی برنامه کامنت کردهایم و در ادامه آبجکتی از روی کلاس Father
به نام fatherObject
ساخته و کلیۀ متدهای مربوط به کلاس Grandfather
به همراه دو متد جدید مربوط به کلاس Father
را روی آبجکت fatherObject
فراخوانی کردهایم و با اجرای برنامۀ فوق در خروجی خواهیم داشت:
Short
Bright
Bald
Well-behaved
Creative
Active
Iranian
BA
Much
همانطور که در خروجی برنامه مشاهده میکنیم، کلاس Father
کلیۀ خصوصیات کلاس Grandfather
را به ارث برده است با این تفاوت که عملکرد متدهای ()showGrandfatherBehavior
و ()showGrandfatherCreativity
را در کلاس Father
تغییر دادهایم بدین صورت که مقدار اتریبیوتهای behavior
و creativity
را در آن به ترتیب معادل استرینگهای «Well-behaved» و «Creative» قرار داده و به عبارتی متدهای مذکور را اُورراید کردهایم. به علاوه، متدهای دیگری هم به کلاس Father
افزودهایم تا در آنها اتریبیوتهایی همچون «BA» و «Much» را تعریف نماییم.
در این مرحله به پیادهسازی کلاس Son
میپردازیم به طوری که کلاس مذکور از کلاس Father
ارثبری نماید که برای این منظور فایل کلاس Son
را باز نموده و آن را به صورت زیر تکمیل میکنیم:
public class Son extends Father{
}
در حقیقت، از آنجایی که میخواهیم کلاس Son
کلیۀ خصوصیات خود را از کلاس Father
به ارث ببرد، کلیدواژۀ extends
را نوشته سپس نام کلاس Father
را مینویسیم. نکتۀ قابلتوجه در ارتباط با ارثبری کلاس Son
از کلاس Father
این است که به دلیل ارثبری کلاس Father
از کلاس Grandfather
و همچنین ارثبری کلاس Son
از کلاس Father
میتوان گفت که کلاس Son
آن دسته از خصوصیاتی که کلاس Father
از کلاس Grandfather
به ارث برده را نیز به ارث میبرد که برای درک بهتر آنچه که در بالا بدان اشاره کردیم، به آموزش قبل مراجعه کرده و میبینیم که پسر خصوصیاتی به صورت زیر دارا است:
- بر خلاف پدر و پدربزرگ خود، قدبلند است.
- اصلاً طاس نیست.
- همانند پدربزرگ خود عصبانی است.
- بر خلاف پدرش، تحصیلات فوقلیسانس دارد.
- در نهایت خیلی هم اهل مطالعه است.
حال با آگاهی از این موارد، میتوانیم کد مربوط به کلاس Son
را به صورت زیر ویرایش نماییم:
public class Son extends Father {
@Override
public void showGrandfatherHeight() {
String height = "Tall";
System.out.println(height);
}
@Override
public void showGrandfatherBaldness() {
String baldness = "Not Bald";
System.out.println(baldness);
}
@Override
public void showGrandfatherBehavior() {
String behavior = "Angry";
System.out.println(behavior);
}
@Override
public void showFatherEducation() {
String education = "MA";
System.out.println(education);
}
@Override
public void showFatherStudyTime() {
String studyTime = "Very Much";
System.out.println(studyTime);
}
}
همانطور که در کد فوق مشاهده میکنیم، با استفاده از دستور Override@
متد ()showGrandfatherHeight
را اُورراید میکنیم بدین صورت که مقدار اتریبیوت height
را برابر با استرینگ «Tall» قرار میدهیم مضاف بر اینکه متد ()showGrandfatherBaldness
را نیز اُورراید کرده و مقدار اتریبیوت baldness
در آن را برابر با استرینگ «Not Bald» قرار میدهيم. به همين ترتيب، متدهای ()showGrandfatherBehavior
و ()showFatherEducation
و همچنین متد ()howFatherStudyTime
اُورراید شده و به ترتیب اتریبیوتهای behavior
،education
و studyTime
در آنها برابر با استرینگهای «Angry» ،«MA» و «Very Much» قرار داده میشوند.
سؤالی که در اینجا ممکن است مطرح شود این است که «چرا متد مربوط به اتریبیوت behavior
در کلاس Son
از کلاس Grandfather
اُورراید شده است در حالی که این خصوصیت مابین پسر و پدربزرگ مشترک میباشد؟» در پاسخ بدین سؤال میتوان گفت که پدر کلیهٔ خصوصیات خود را از پدربزرگ به ارث برده اما بر خلاف پدربزرگ فردی خوشاخلاق است و از همین روی متد ()showGrandfatherBehavior
در کلاس Father
از کلاس Grandfather
اُورراید شده و مقدار اتریبیوت behavior
از کلاس Grandfather
به استرینگ «Well-behaved» در این کلاس تغییر یافته است. حال از آنجایی که پسر بر خلاف پدر فردی عصبانی بوده و همچنین خصوصیت عصبانی بودن را از پدربزرگ خود به ارث برده است، مجدداً مجبور به اُورراید کردن متد مربوط به اتریبیوت behavior
در کلاس Son
از کلاس Grandfather
میباشیم. اکنون میتوانیم به کلاس ActionClass
رفته و آن را به شکل زیر بازنویسی کنیم:
public class ActionClass {
public static void main(String[] args) {
// Grandfather grandfatherObject = new Grandfather();
// grandfatherObject.showGrandfatherHeight();
// grandfatherObject.showGrandfatherSkinColor();
// grandfatherObject.showGrandfatherBaldness();
// grandfatherObject.showGrandfatherBehavior();
// grandfatherObject.showGrandfatherCreativity();
// grandfatherObject.showGrandfatherActivity();
// grandfatherObject.showGrandfatherNationality();
// Father fatherObject = new Father();
// fatherObject.showGrandfatherHeight();
// fatherObject.showGrandfatherSkinColor();
// fatherObject.showGrandfatherBaldness();
// fatherObject.showGrandfatherBehavior();
// fatherObject.showGrandfatherCreativity();
// fatherObject.showGrandfatherActivity();
// fatherObject.showGrandfatherNationality();
// fatherObject.showFatherEducation();
// fatherObject.showFatherStudyTime();
Son sonObject = new Son();
sonObject.showGrandfatherHeight();
sonObject.showGrandfatherSkinColor();
sonObject.showGrandfatherBaldness();
sonObject.showGrandfatherBehavior();
sonObject.showGrandfatherCreativity();
sonObject.showGrandfatherActivity();
sonObject.showGrandfatherNationality();
sonObject.showFatherEducation();
sonObject.showFatherStudyTime();
}
}
همانطور که در کد فوق مشاهده میشود، کلیۀ کدهای پیشین را کامنت کردهایم سپس آبجکتی از روی کلاس Son
به اسم sonObject
ساخته و در ادامه کلیۀ متدهای تعریفشده در کلاس مذکور را روی آبجکت ساختهشده از روی آن فراخوانی کردهایم که پس از اجرای برنامۀ فوق در خروجی خواهیم داشت:
Tall
Bright
Not Bald
Angry
Creative
Active
Iranian
MA
Very Much
همانطور که مشاهده میکنیم، خروجی اول نشانگر اولین اُورراید در کلاس Son
است که در آن متد ()showGrandfatherHeight
را رونویسی کردیم و خروجی دوم مربوط به اُورراید کردن متد ()showGrandfatherBaldness
میباشد و به همین ترتیب خروجی حاصل از اُورراید کردن متدهای دیگر را مشاهده میکنیم.