ارث بری (inheritance) در جاوا
در سری مقالات آموزش شی گرایی در جاوا, میخواهیم مفهوم ارث بری را بررسی کنیم.
در مقاله قبل مقدمات و مفاهیم اولیه شی گرایی را تعریف کردیم. مفاهیمی همچون متد ها, کلاس ها و object ها بررسی شد. مشخص شد که شی گرایی میتواند یه راه بهبود یافته برای کد نویسی باشد. زیرا بسیاری از افزونگی کد ها حذف میشوند و اجزا و داده های برنامه با ساختار مشخص در برنامه مورد استفاده قرار میگیرند. همچنین چون ماهیت جاوا یک زبان شی گرایی است, حتی اگر نخواهیم کلاس هایی ایجاد کنیم, برای استفاده از ابزار جاوا نیاز به استفاده از شی گرایی است. پس برای کد نویسی بهتر در جاوا داشتن اطلاعات پیرامون مفاهیم پایه ای آن که شی گرایی است , قدم اول آموزش جاوا است.
ارث بری اولین مفهومی است که به آن میپردازیم. همانطور که از کلمه ارث بری مشخص است به عملی گفته میشود که یک موجود از موجود دیگری بخشی و یا تمام ویژگی ها, داشته ها و خواص آن را بگیرد. این موجود میتواند انسان باشد. یک انسان از والدین خود یکسری خصوصیات اخلاقی را به ارث میبرد و همچنین یکسری از داشته های والدین برای وی نیز میباشد. علاوه بر انسان, موجود میتواند کلاس در زبان برنامه نویسی باشد. باز هم همانطور که از تعریف بر میآید یکسری از خصوصیات کلاسی که از آن ارث بری میکند را دارد.
همانطور که در مقاله قبل اشاره شد, متد ها و متغیر های private تنها از طریق کلاسی که در آن وجود دارند قابل استفاده و دسترسی است و حتی در ارث بری نیز دسترسی به آن ممکن نیست. باقی متد ها و متغیر ها برای کلاس ارث برنده قابل استفاده است. برای مثال کد زیررا در نظر بگیرید :
public class Father { private String firstName="Father"; protected String lastName = "User"; public void printInfo(String firstName, String lastName) { System.out.println("you are : " + firstName + " " + lastName); } public void printMe() { printInfo(firstName, lastName); } } class Son extends Father{ private String firstName = "Son"; public void printMe() { System.out.println("i'm different"); printInfo(firstName, lastName); } } class Run{ public static void main(String[] args) { Father father = new Father(); Son son=new Son(); father.printMe(); son.printMe(); } }
همانطور که در کد بالا مشخص است نام خانوادگی در کلاس Father به صورت public میباشد و از کلاس Son قابل استفاده میباشد. اما firstName در کلاس Father به صورت Private است و در کلاس Son اگر بخواهیم این متغیر را داشته باشیم نیاز است تا آن را تعریف کنیم. متد printInfo در Father در کلاس Son نیز قابل استفاده است. اما متد printMe با اینکه در کلاس Father پیاده سازی شده است با این حال در کلاس Son نیز پیاده سازی شده است. وقتی از object این دو کلاس میخواهیم متد printMe را انتخاب کنیم چون در هر دو کلاس تعریف شده است و در هر کلاسی به نوع متفاوتی از کلاس دیگر پیاده سازی شده است, خروجی متفاوتی را نیز دریافت میکنیم ( توجه داشته باشید تفاوت در خروجی منظور چاپ i’m different است) . وقتی با متدی مانند printMe برخورد میشود, از واژه Override استفاده میشود و در کلاس ارث برنده میتوان آن را با استفاده از annotation نمایش داد :
@Override public void printMe() { System.out.println("i'm different"); printInfo(firstName, lastName); }
کد بالا به این معنا میباشد که این متد در کلاسی که از آن ارث بری کرده است وجود دارد و به طرز دیگری ( به منظور افزودن کد به آن ) پیاده سازی شده است. البته معنای دیگری نیز دارد که در ادامه به آن میپردازیم. گاهی کاربران و خوانندگان بین واژه override و overload دچار سردرگمی میشوند. برای رفع این سردرگمی بهتر است تعریف overload در جاوا را بررسی کنیم. وقتی یک متد هم نام با متد دیگری باشد و تنها در نوع و تعداد پارامتر هایی که دریافت میکند با متد اولیه متفاوت باشد, عمل overload شدن اتفاق میافتد. البته باید توجه کنید که در هنگام overload میتوان مقداری که برمیگرداند نیز متفاوت باشد اما نوع و یا تعداد پارامتر های ورودی آن حتما باید متفاوت باشد. برای مثال در اینجا انواع روش های overload شدن نمایش داده شده است. :
@Override public void printMe() { System.out.println("i'm different"); printInfo(firstName, lastName); } public void printMe(String message) { System.out.println(message); printInfo(firstName, lastName); } private int printMe(String s1, String s2) { int age = 2; printInfo(s1, s2); return age; } public String printMe(int age) { String message = "i'm message"; printInfo(firstName, lastName); return message; }
نکته بعدی و مهم در مبحث ارث بری, وجود constructor در کلاسی است که از آن ارث بری میشود. در ابتدا باید با واژه super آشنا شویم. همانطور که از کلمه this برای اشاره به درون کلاس استفاده میشد, از super برای اشاره به کلاسی که از آن ارث میبریم, استفاده میشود.
public void hello() { super.printMe(); }
اجرای این متد در کلاس Son چنین خروجی میدهد :
you are : Father User
اما وقتی در کلاسی که از آن ارث بری میشود constructor با مقادیر باشد, نیاز است تا در ابتدای ایجاد ارث برنده از آن نیز این مقادیر تعریف شوند و به کلاسی که از آن ارث برده میشود ارسال شود مانند :
public class Father { protected String lastName = "User"; private String firstMame; public Father(String firstMame) { this.firstMame = firstMame; } public void printInfo(String firstName, String lastName) { System.out.println("you are : " + firstName + " " + lastName); } public void printMe() { printInfo(firstMame, lastName); } } class Son extends Father{ public Son(String firstMame) { super(firstMame); this.firstName = firstMame; } private String firstName = "Son"; public void printMe() { printInfo(firstName, lastName); } } class Run{ public static void main(String[] args) { Father father = new Father("Father"); Son son = new Son("Son"); father.printMe(); son.printMe(); } }
در کد بالا کلاس Father به یک پارامتر ورودی از نوع String نیاز داشت. کلاس Son نیز چون از آن ارث بری کرده است باید حداقل در Constructor خود یک String را از طریق دستور super به کلاس Father ارسال کند. این مقدار میتواند به عنوان پارامتر نباشد و مستقیما یک String بجای آن قرار بگیرد مانند :
public Son(String firstMame) { super("Son"); this.firstName = firstMame; }
اما باید توجه داشته باشید که super تنها در اولین خط کد در constructor میتواند قرار بگیرید.
در این مقاله سعی شد تا به مفهوم ارث بری در جاوا بپردازیم. در مقاله بعد به مفاهیم abstract و interface در جاوا میپردازیم.
سری مقالات آموزش شی گرایی در جاوا همچنان ادامه دارد.
با ما همراه باشید.
دیدگاهتان را بنویسید
برای نوشتن دیدگاه باید وارد بشوید.