فصل 19: چندریختی (Polymorphism) و اتصال دینامیک (Dynamic Binding) در جاوا

28 مرداد 1397
polymorphism-java

پلی مورفیسم یا چندریختی مفهومی است که به معنای انجام یک کار به چندین شکل است. پلی مورفیسم ترکیبی از دو واژه پلی و مورفیسم است؛ در زبان یونانی، پلی به معنای چندین و مورفیسم به معنای فرم دادن است.

دو نوع چندریختی در جاوا وجود دارد، چندریختی در زمان کامپایل و چندریختی در زمان اجرا؛ با استفاده از روش های اورلود و اورراید متدها برای دستیابی به پلی مورفیسم استفاده می شود.

اگر یک متد استاتیک را اورلود کنید، آنگاه چندریختی در زمان کامپایل انجام شده است. در ادامه مطلب درباره چندریختی در زمان اجرا بحث می کنیم.

چندریختی در زمان اجرا در جاوا

چندریختی در زمان اجرا (Runtime Polymorphism) یا گسل متد دینامیک (Dynamic Method Dispatch) پروسه‌ای است که طبق آن صدا زدن متدهای اورراید شده در زمان اجرا بررسی می شود به جای زمان کامپایل.

در این پروسه، یک متد اورراید شده، توسط یک متغیر رفرنس سوپرکلاس صدا زده می شود. این که کدام متد باید صدا زده شود بستگی به شی‌ای دارد که صدا زده می شود.

بیاید ابتدا مفهوم Upcasting را بررسی کنیم.

Upcasting

در صورتی که متغیر رفرنس کلاس والد، به شی ساخته شده از کلاس فرزند اشاره کند. Upcasting اتفاق افتاده است.

class A{}  
class B extends A{}
A a=new B();//upcasting

برای Upcasting می توان از متغیر رفرنس کلاس یا اینترفیس (رابط) استفاده کرد. توجه کنید:

interface I{}  
class A{}  
class B extends A implements I{}

رابطه کلاس B به شکل زیر میباشد:

B IS-A A
B IS-A I
B IS-A Object

از آنجایی که تمام کلاس ها در جاوا از کلاس Object ارث بری می کند پس کلاس B هم فرزند کلاس A می باشد.

مثال چندریختی زمان اجرا

به عنوان مثال دو کلاس Bike و Splendor وجود دارد که کلاس Splendor از Bike ارث بری می کند. همانطور که می بینید کلاس Splendor متد run را اورراید کرده است. از آنجایی که شی ساخته شده از نوع کلاس فرزند می باشد، متد run اورراید شده اجرا می شود.

مثال:

class Bike{  
  void run(){System.out.println("running");}  
}  
class Splendor extends Bike{  
  void run(){System.out.println("running safely with 60km");}  
  
  public static void main(String args[]){  
    Bike b = new Splendor();//upcasting  
    b.run();  
  }  
}

خروجی:

running safely with 60km.

چندریختی (Polymorphic) در جاوا

در مثال زیر چندریختی را در مثال بانک که قبلا هم بررسی کردیم، مشاهده می کنیم. یک کلاس پدر برای بانک ها وجود دارد اما هر بانک برای خودش نرخ بهره متفاوتی دارد.

مثال:

class Bank{  
float getRateOfInterest(){return 0;}  
}  
class SBI extends Bank{  
float getRateOfInterest(){return 8.4f;}  
}  
class ICICI extends Bank{  
float getRateOfInterest(){return 7.3f;}  
}  
class AXIS extends Bank{  
float getRateOfInterest(){return 9.7f;}  
}  
class TestPolymorphism{  
public static void main(String args[]){  
Bank b;  
b=new SBI();  
System.out.println("SBI Rate of Interest: "+b.getRateOfInterest());  
b=new ICICI();  
System.out.println("ICICI Rate of Interest: "+b.getRateOfInterest());  
b=new AXIS();  
System.out.println("AXIS Rate of Interest: "+b.getRateOfInterest());  
}  
}

خروجی:

SBI Rate of Interest: 8.4
ICICI Rate of Interest: 7.3
AXIS Rate of Interest: 9.7

مثال زیر درباره شکل های هندسی است:

مثال:

class Shape{  
void draw(){System.out.println("drawing...");}  
}  
class Rectangle extends Shape{  
void draw(){System.out.println("drawing rectangle...");}  
}  
class Circle extends Shape{  
void draw(){System.out.println("drawing circle...");}  
}  
class Triangle extends Shape{  
void draw(){System.out.println("drawing triangle...");}  
}  
class TestPolymorphism2{  
public static void main(String args[]){  
Shape s;  
s=new Rectangle();  
s.draw();  
s=new Circle();  
s.draw();  
s=new Triangle();  
s.draw();  
}  
}

خروجی:

drawing rectangle...
drawing circle...
drawing triangle...

مثالی هم درباره حیوانات ببینیم:

مثال:

class Animal{  
void eat(){System.out.println("eating...");}  
}  
class Dog extends Animal{  
void eat(){System.out.println("eating bread...");}  
}  
class Cat extends Animal{  
void eat(){System.out.println("eating rat...");}  
}  
class Lion extends Animal{  
void eat(){System.out.println("eating meat...");}  
}  
class TestPolymorphism3{  
public static void main(String[] args){  
Animal a;  
a=new Dog();  
a.eat();  
a=new Cat();  
a.eat();  
a=new Lion();  
a.eat();  
}}

خروجی:

eating bread...
eating rat...
eating meat...

چندریختی در فیلدهای کلاس

همانطور که می دانید، متدها را میتوان اورراید کرد اما دستیابی به چندریختی توسط فیلدهای کلاس امکان پذیر نیست.

در مثال زیر، برخلاف مثال های بالا که که متد کلاس فرزند به دلیل ویژگی چندریختی اجرا میشد، از آنجایی که فیلدها اورراید نمی شود، در مثال پایین فیلد مربوط به کلاس پدر در دسترس است.

class Bike{  
 int speedlimit=90;  
}  
class Honda3 extends Bike{  
 int speedlimit=150;  
  
 public static void main(String args[]){  
  Bike obj=new Honda3();  
  System.out.println(obj.speedlimit);//90  
}

خروجی:

90

چندریختی با وراثت چندسطحی

به مثال زیر توجه کنید:

مثال:

class Animal{  
void eat(){System.out.println("eating");}  
}  
class Dog extends Animal{  
void eat(){System.out.println("eating fruits");}  
}  
class BabyDog extends Dog{  
void eat(){System.out.println("drinking milk");}  
public static void main(String args[]){  
Animal a1,a2,a3;  
a1=new Animal();  
a2=new Dog();  
a3=new BabyDog();  
a1.eat();  
a2.eat();  
a3.eat();  
}  
}

خروجی:

eating
eating fruits
drinking Milk

و در ادامه داریم:

مثال:

class Animal{  
void eat(){System.out.println("animal is eating...");}  
}  
class Dog extends Animal{  
void eat(){System.out.println("dog is eating...");}  
}  
class BabyDog1 extends Dog{  
public static void main(String args[]){  
Animal a=new BabyDog1();  
a.eat();  
}}

خروجی:

Dog is eating

از آنجایی که BabyDog متد eat را اورراید نکرده است، متد eat در Dog صدا زده می شود.

اتصال دینامیک (Dynamic Binding) در جاوا

به اتصال بدنه متد به فراخوان متد اتصال یا Binding می گویند. در کل دو نوع اتصال وجود دارد:

  • اتصال دینامیک یا اتصال دیر
  • اتصال استاتیک یا اتصال زود

نوع یا Type چیست

1- نوع متغیرها

هر متغیری یک نوع دارد که می تواند اولیه یا غیر اولیه باشد.

int data=30;

در مثال بالا، این متغیر از نوع int است.

2- نوع رفرنس ها

class Dog{  
 public static void main(String args[]){  
  Dog d1;//Here d1 is a type of Dog  
 }  
}

3- نوع شی‌ها

اشیا نمونه ای از یک کلاس هستند اما همزمان نمونه ای از کلاس‌های والد خود نیز می باشند.

class Animal{}  
  
class Dog extends Animal{  
 public static void main(String args[]){  
  Dog d1=new Dog();  
 }  
}  

به عنوان مثال، d1 هم نمونه Dog و هم نمونه Animal می باشد.

اتصال استاتیک

در صورتی که نوع یک شی در موقع کامپایل توسط کامپایلر تشخیص داده شود، اتصال استاتیک رخ داده است.

در صورت وجود متدهای private، final یا استاتیک در کلاس، اتصال استاتیک رخ می دهد.

مثال:

class Dog{  
 private void eat(){System.out.println("dog is eating...");}  
  
 public static void main(String args[]){  
  Dog d1=new Dog();  
  d1.eat();  
 }  
}

اتصال دینامیک

در صورتی که نوع شی هنگام اجرا مشخص شود، آنگاه اتصال دینامیک رخ داده است.

مثال:

class Animal{  
 void eat(){System.out.println("animal is eating...");}  
}  
  
class Dog extends Animal{  
 void eat(){System.out.println("dog is eating...");}  
  
 public static void main(String args[]){  
  Animal a=new Dog();  
  a.eat();  
 }  
}

خروجی:

Output:dog is eating...

در مثال بالا، نوع شی توسط کامپایلر مشخص نمی شود زیرا هر نمونه از Dog یک نمونه Animal می باشد و کامپایلر نوع شی را دقیقا نمی داند.

نویسنده شوید
دیدگاه‌های شما (1 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

Mahdi
16 شهریور 1398
بی نظیر بعد از کلی مقاله و کتاب امروز درست مفهوم پلی مورفیسم رو فهمیدم

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.