آموزش ارث بری یا وراثت (Inheritance) در جاوا
در این آموزش از کتاب برخط جاوا، ارث بری یا وراثت (Inheritance) را می توان پردازشی تعریف کرد، که در آن یک کلاس خصوصیات (متدها و فیلدها) کلاسی دیگر را بدست می آورد. با استفاده از ارث بری، اطلاعات قابلیت مدیریت به صورت سلسه مراتبی را خواهند داشت.
کلاسی که خصوصیات کلاس دیگری را ارث بری می نماید کلاس فرزند، و کلاسی که خصوصیات آن به ارث برده شده است را کلاس پدر می نامیم.
کلمه کلیدی extends در وراثت
extends کلمه کلیدی ای است که برای ارث بری خصوصیات یک کلاس استفاده می شود. مثال زیر نحوه استفاده از extends را نشان می دهد:
class Super {
.....
.....
}
class Sub extends Super {
.....
.....
}
نمونه کد
مثال زیر وراثت در جاوا را شرح می دهد. در این مثال، دو کلاس با نام های Calculation و My_Calculation را مشاهده می کنید. با استفاده از کلمه کلیدی extends، کلاس My_Calculation متد های addition() و substraction() موجود در کلاس Calculation را ارث بری می نماید. برنامه زیر را در فایلی با نام My_Calculation.java کپی کنید.
class Calculation {
int z;
public void addition(int x, int y) {
z = x y;
System.out.println("The sum of the given numbers:" z);
}
public void subtraction(int x, int y) {
z = x - y;
System.out.println("The difference between the given numbers:" z);
}
}
public class My_Calculation extends Calculation {
public void multiplication(int x, int y) {
z = x * y;
System.out.println("The product of the given numbers:" z);
}
public static void main(String args[]) {
int a = 20, b = 10;
My_Calculation demo = new My_Calculation();
demo.addition(a, b);
demo.Subtraction(a, b);
demo.multiplication(a, b);
}
}
کامپایل و اجرای کد بالا در زیر نشان داده شده است.
javac My_Calculation.java
java My_Calculation
خروجی برنامه:
The sum of the given numbers:30
The difference between the given numbers:10
The product of the given numbers:200
در برنامه داده شده، زمانی که یک شیء از My_Calculation ایجاد می شود، یک کپی از محتویات پدر درون آن قرار می گیرد. به همین خاطر است که با استفاده از کلاس فرزند یا subclass شما می توانید به خصوصیات پدر یا superclass دسترسی پیدا کنید.
متغیر reference کلاس پدر می تواند شیء کلاس فرزند را قبول کند، ولی با استفاده از این متغیر شما تنها می توانید به خصوصیات پدر دسترسی پیدا کنید، بنابراین توجه داشته باشید که برای دسترسی به خصویات هر دو، توصیه می شود که متغیر reference را با کلاس فرزند ایجاد کنید.
همانطور که برنامه بالا را ملاحظه می کنید، شما می توانید کلاس را همانند زیر مقدار دهی کنید. ولی با استفاده از متغیر reference کلاس پدر (که در مثال زیر cal نام دارد) شما نمی توانید متد multiplication() را که متعلق به فرزند یعنی My_Calculation است را فراخوانی کنید.
توجه : کلاس فرزند تمامی اعضای (متدها، فیلدها، کلاس های nested) پدر را به ارث می برد. Cunstructor ها جزء اعضاء نیستند، بنابراین آن ها توسط فرزند به ارث برده نمی شوند، ولی constructor یا سازنده ی پدر می تواند در فرزند فراخوانی شود.
کلمه کلیدی super
کلمه کلیدی super همانند کلمه کلیدی this می باشد. در زیر مواردی را که در آن از super استفاده می شود آمده است.
- در صورتی که اعضای پدر و فرزند هم نام باشند، برای متمایر کردن آن ها، استفاده می شود.
- برای فراخوانی سازنده یا constructor پدر درون فرزند استفاده می شود.
متمایز کردن اعضاء
اگر کلاسی خصوصیات کلاس دیگر را ارث بری کند. و اگر اعضای (متدها، فیلدها ...) کلاس پدر اسامی همسان با اسامی اعضای کلاس فروند داشته باشند، برای متمایز کردن این متغیر ها ما همانند زیر از کلمه کلیدی super استفاده می کنیم.
super.variable
super.method();
نمونه کد
در زیر مثالی برای شرح استفاده از کلمه کلیدی super در وراثت آورده شده است، برنامه زیر دارای دو کلاس به نام های Child و Parent می باشد، هر دو دارای متدی با نام display() ولی با پیاده سازی متفاوت هستند، و همچنین دارای متغیری به نام num با مقادیر متفاوت. ما متد display() هر دو را فراخوانی می کنیم و همچنین مقدار متغیر num هر دو را چاپ می کنیم. در اینجا شما استفاده از کلمه کلیدی super و متمایز کردن اعضای هر دو کلاس را مشاهده می کنید.
class Parent {
int num = 20;
// display method of Parent
public void display() {
System.out.println("This is the display method of Parent");
}
}
public class Child extends Parent {
int num = 10;
// display method of Child
public void display() {
System.out.println("This is the display method of Child");
}
public void my_method() {
// Instantiating Child
Child sub = new Child();
// Invoking the display() method of Child
sub.display();
// Invoking the display() method of Parent
super.display();
// printing the value of variable num of Child
System.out.println("value of the variable named num in Child:" sub.num);
// printing the value of variable num of Parent
System.out.println("value of the variable named num in Parent:" super.num);
}
public static void main(String args[]) {
Child obj = new Child();
obj.my_method();
}
}
خروجی
This is the display method of Child
This is the display method of Parent
value of the variable named num in Child:10
value of the variable named num in Parent:20
فراخوانی Constructor کلاس پدر
در صورتی که کلاسی خصوصیات کلاسی دیگر را ارث بری کند، کلاس فرزند به طور خودکار constructor پیشفرض پدر را بدست می آورد. ولی اگر بخواهید contructor دارای پارامتر کلاس پدر را فراخوانی کنید، نیاز خواهید داشت مانند زیر از کلمه کلید super استفاده کنید.
super(values);
نمونه کد
برنامه زیر شرح استفاده از کلمه کلیدی super برای فراخوانی constructor دارای پارامتر کلاس نشان داده شده است. این برنامه حاوی یک کلاس پدر و کلاس فرزند می باشد، که کلاس پدر یک constructor دارای پارامتر دارد که یک مقدار رشته را قبول می کند.
class Parent {
int age;
Parent(int age) {
this.age = age;
}
public void getAge() {
System.out.println("The value of the variable named age in Parent is: " + age);
}
}
public class Child extends Parent {
Child(int age) {
super(age);
}
public static void main(String argd[]) {
Child s = new Child(24);
s.getAge();
}
}
خروجی
The value of the variable named age in Parent is: 24
رابطه IS-A
در مفاهیم شیءگرایی رابطه IS-A را می توان این چنین بیان کرد که: یک شیء نوعی از یک شیء دیگر است. اجازه دهید ببینیم که کلمه کلیدی extends چگونه برای وراثت یا ارث بری (Inheritance) در زبان جاوا استفاده می شود.
public class Animal {
}
public class Mammal extends Animal {
}
public class Reptile extends Animal {
}
public class Dog extends Mammal {
}
بر اساس مثال بالا، در مفاهیم شیءگرا و وراثت موارد زیر درست می باشند:
- Animal پدر Mammal است.
- Animal پدر Reptile است.
- Mammal و Reptile کلاس های فرزند Animal هستند.
- Dog فرزند هر دو کلاس Mammal و Animal است.
با توجه به رابطه IS-A، می توان عبارات زیر را بیان کرد:
- Mammal یک Animal است.
- Reptile یک Animal است.
- Dog یک Mammal است.
- Dog همچنین یک Animal نیز است.
با استفاده از کلمه کلیدی extends در جاوا (Java)، کلاس های فرزند قادر خواهند بود تمامی خصوصیات کلاس پدر را ارث بری کنند، البته به جز خصوصیاتی که در کلاس پدر به طور private تعریف شده اند.
با استفاده از عملگر instanceof می تواند اطمینان حاصل کرد که، Mammal در واقع یک Animal است.
مثال:
class Animal {
}
class Mammal extends Animal {
}
class Reptile extends Animal {
}
public class Dog extends Mammal {
public static void main(String args[]) {
Animal a = new Animal();
Mammal m = new Mammal();
Dog d = new Dog();
System.out.println(m instanceof Animal);
System.out.println(d instanceof Mammal);
System.out.println(d instanceof Animal);
}
}
خروجی برنامه:
true
true
true
پس از درک کلمه کلیدی extends در وراثت، اجازه دهید نگاهی به کلمه کلیدی implements، جهت استفاده در رابطه IS-A بیاندازیم.
کلمه کلیدی implements جهت استفاده کلاس ها برای ارث بری از interface ها بکار می رود. interface ها هرگز نمی توانند توسط کلاس ها extends شوند.
مثال:
public interface Animal {}
public class Mammal implements Animal {
}
public class Dog extends Mammal {
}
کلمه کلیدی instanceof
اجازه دهید جهت بررسی اینکه Mammal در واقع یک Animal و Dog در واقع یک Animal می باشد را با استفاده از کلمه کلیدی instanceof انجام دهیم.
interface Animal{}
class Mammal implements Animal{}
public class Dog extends Mammal{
public static void main(String args[]){
Mammal m = new Mammal();
Dog d = new Dog();
System.out.println(m instanceof Animal);
System.out.println(d instanceof Mammal);
System.out.println(d instanceof Animal);
}
}
خروجی برنامه:
true
true
true
رابطه HAS-A
این نوع رابطه اساسا مبنی بر استفاده می باشد. این رابطه تعیین می کند که آیا یک کلاس دارای خصوصیتی از نوع یک کلاس دیگر می باشد یا خیر. این نوع رابطه باعث کاهش کدهای تکراری و همچنین باگ ها در برنامه می شود.
اجازه دهید مثالی بیاوریم:
public class Vehicle {}
public class Speed {}
public class Van extends Vehicle {
private Speed sp;
}
این نشان می دهد که Van دارای Speed می باشد. با داشتن یک کلاس جدای Speed، دیگر نیازی به قرار دادن تمامی کدهای مربوط به سرعت (Speed) درون Van نیست. که این باعث می باشد که از Speed بتوان در برنامه های دیگر دوباره استفاده کرد.
نکته بسیار مهم در جاوا این است که، یک کلاس می تواند تنها از یک کلاس دیگر ارث بری کند. بدین معنی که یک کلاس نمی تواند از بیشتر از یک کلاس ارث بری کند. بنابراین کد زیر اشتباه است:
public class Dog extends Animal, Mammal {}
با این وجود، یک کلاس می تواند از یک یا بیشتر از interface ها ارث بری کند. این جاوا را از غیر ممکن بودن وراثت (Inheritance) چندگانه رهایی می دهد.