وراثت
وراثت به یک کلاس اجازه میدهد که خصوصیات یا متدهایی را از کلاس دیگر به ارث برد. وراثت مانند رابطه پدر و پسری میماند به طوریکه فرزند خصوصیاتی از قبیل قیافه و رفتار را از پدر خود به ارث برده باشد.
همه متد و خصوصیات کلاس پایه میتوانند در کلاس مشتق مورد استفاده قرار بگیرند به استثنای اعضا و متدهای با سطح دسترسی private. همه کلاسها در جاوا از کلاس Object ارث بری میکنند. مفهوم اصلی وراثت در مثال زیر نشان داده شده است :
1: package myfirstprogram; 2: 3: class Parent 4: { 5: private String message; 6: 7: public void setMessage(String message) 8: { 9: this.message = message; 10: } 11: 12: public String getMessage() 13: { 14: return message; 15: } 16: 17: public void ShowMessage() 18: { 19: System.out.println(message); 20: } 21: 22: public Parent(String message) 23: { 24: this.message = message; 25: } 26: } 27: 28: class Child extends Parent 29: { 30: public Child(String message) 31: { 32: super(message); 33: } 34: }
در این مثال دو کلاس با نامهای Parent و Child تعریف شده است. در این مثال یک فیلد را با سطح دسترسی private (خط 5) و خاصیت مربوط به آن را با سطح دسترسی public (خط 15-7) تعریف کردهایم. سپس یک متد را برای نمایش پیام تعریف کردهایم. یک سازنده در کلاس Parent تعریف شده است که یک آرگومان از نوع رشته قبول میکند و یک پیغام نمایش میدهد (خطوط 25-22). حال به کلاس Child توجه کنید (خط 34-28). این کلاس تمام متدها و خاصیتهای کلاس Parent را به ارث برده است. نحوه ارث بری یک کلاس به صورت زیر است :
class DerivedClass extends BaseClass
براحتی میتوان با قرار دادن کلمه کلیدی extends بعد از نام کلاس و سپس نوشتن نام کلاسی که از آن ارث بری میشود (کلاس پایه) این کار را انجام داد. در داخل کلاس Child هم یک سازنده ساده وجود دارد که یک آرگومان رشتهای قبول میکند. وقتی از وراثت در کلاسها استفاده میکنیم، هم سازنده کلاس مشتق و هم سازنده پیشفرض کلاس پایه هر دو اجرا میشوند. سازنده پیشفرض یک سازنده بدون پارامتر است. اگر برای یک کلاس سازندهای تعریف نکنیم کامپایلر به صورت خودکار یک سازنده برای آن ایجاد میکند.
اگر هنگام صدا زدن سازنده کلاس مشتق بخواهیم سازنده کلاس پایه را صدا بزنیم باید از کلمه کلیدی super استفاده کنیم. کلمه کلیدی super یک سازنده از کلاس پایه را صدا می زند.
در مثال بالا به وسیله تأمین مقدار پارامتر message سازنده کلاس مشتق و ارسال آن به داخل پرانتز کلمه کلیدی super ، سازنده معادل آن در کلاس پایه فراخوانی شده و مقدار message را به آن ارسال میکند. سازنده کلاس Parent هم این مقدار (مقدار message) را در یک عضو دادهای (فیلد) private قرار میدهد. میتوانید کدهایی را به داخل بدنه سازنده Child اضافه کنید تا بعد از سا زنده Parent اجرا شوند. اگر از کلمه کلیدی super استفاده نشود به جای کلاس پایه سازنده پیشفرض فراخوانی میشود. اجازه بدهید که اشیایی از کلاسهای Parent و Child بسازیم تا نشان دهیم که چگونه کلاس Child متدها و خواص کلاس Parent را به ارث میبرد.
1: public class MyFirstProgram 2: { 3: 4: public static void main(String[] args) 5: { 6: Parent myParent = new Parent("Message from parent."); 7: Child myChild = new Child("Message from child."); 8: 9: myParent.ShowMessage(); 10: 11: myChild.ShowMessage(); 12: 13: myParent.setMessage("Modified message of the parent."); 14: myParent.ShowMessage(); 15: 16: myChild.setMessage("Modified message of the child."); 17: myChild.ShowMessage(); 18: 19: //myChild.message; ERROR: can't access private members of base class 20: } 21: }
Message from parent. Message from child. Modified message of the parent. Modified message of the child.
هر دو شیء را با استفاده از سازندههای مربوط به خودشان مقدار دهی میکنیم. (خطوط 7-6) سپس با استفاده از ارث بری و از طریق شیء Child به اعضا و متدهای کلاس Parent دسترسی مییابیم. حتی اگر کلاس Child از کلاس Parent ارث ببرد باز هم اعضای با سطح دسترسی private در کلاس Child قابل دسترسی نیستند (خط 18). سطح دسترسی Protect که در درس آینده توضیح داده خواهد شد به شما اجازه دسترسی به اعضا و متدهای کلاس پایه را میدهد. به نکته دیگر توجه کنید. اگر کلاس دیگری بخواهد از کلاس Child ارث بری کند، باز هم تمام متدها و خواص کلاس Child که از کلاس Parent به ارث برده است را به ارث میبرد.
class GrandChild extends Child { //Empty Body }
این کلاس هیچ چیزی در داخل بدنه ندارد. وقتی کلاس GrandChild را ایجاد میکنید و یک خاصیت از کلاس Parent را فراخوانی میکنید با خطا مواجه میشوید. چون هیچ سازندهای که یک آرگومان رشتهای قبول کند در داخل بدنه GrandChild تعریف نشده است بنابراین شما میتوانید فقط از سازنده پیشفرض یا بدون پارامتر استفاده کنید.
GrandChild myGrandChild = new GrandChild(); myGrandChild.setMessage("Hello my grandchild!"); myGrandChild.ShowMessage();
وقتی یک کلاس ایجاد میکنیم و سازنده GrandChild را فراخوانی میکنیم ابتدا سازنده کلاس Parent فراخوانی میشود و سپس سازنده Child و در نهایت سازنده GrandChild اجرا میشود. برنامه زیر ترتیب اجرای سازندهها را نشان میدهد. دوباره کلاسها را برای خوانایی بیشتر در داخل کدهای جدا قرار میدهیم.
1: package myfirstprogram; 2: 3: class Parent 4: { 5: public Parent() 6: { 7: System.out.println("Parent constructor was called!"); 8: } 9: } 10: 11: class Child extends Parent 12: { 13: public Child() 14: { 15: System.out.println("Child constructor was called!"); 16: } 17: } 18: 19: class GrandChild extends Child 20: { 21: public GrandChild() 22: { 23: System.out.println("GrandChild constructor was called!"); 24: } 25: } 26: 27: public class MyFirstProgram 28: { 29: 30: public static void main(String[] args) 31: { 32: GrandChild myGrandChild = new GrandChild(); 33: } 34: }
Parent constructor was called! Child constructor was called! GrandChild constructor was called!