جاوا (Java) یک زبان برنامه نویسی شیگرا است و پلی مورفیسم (Polymorphism) یکی از مشخصههای اصلی شی گرایی در جاوا و سایر زبانهای برنامه نویسی به حساب میآید. امکان نمایش یک پیام واحد به شکلهای مختلف را پلی مورفیسم میگویند. پلی مورفیسم در برنامه نویسی جاوا نیز باعث شده است که کدهای برنامه سادهتر و کوتاهتر شوند و از پیچیدگی کدها کاسته شود. همچنین، پلی مورفیسم باعث کم شدن تعداد متغیرها و بهبود خوانایی کدها میشود. به پلی مورفیسم ، چند ریختی یا چند شکلی هم گفته میشود. در این مقاله به بررسی کامل پلی مورفیسم در برنامه نویسی جاوا همراه با مثالهای کاربردی برای آن پرداخته شده است.
مفهوم پلی مورفیسم در جاوا
Polymorphism یک قابلیت برای اشیا جاوا به حساب میآید که به کمک آن امکان ظاهر شدن در فرمهای گوناگون فراهم خواهد شد. این مفهوم به نامهای مختلفی از جمله پلی مورفیسم، چند ریختی و چند شکلی شناخته میشود. به بیان سادهتر، پلی مورفیسم در جاوا این امکان را فراهم میکند تا یک عمل به روشهای مختلف انجام شود. هر شی جاوا که بتواند بیش از یک آزمون «IS-A» را پاس کند، می توان گفت که این شی دارای خاصیت چند شکلی است. در جاوا، تمام اشیاء چند شکلی هستند، زیرا تست IS-A را برای نوع (Type) خود و برای کلاس شی گذراندهاند.
در برنامه نویسی شی گرا (Object Oriented Programming | OPP)، مفهوم IS-A کاملاً مبتنی بر وراثت است و میتواند از دو نوع وراثت کلاس (Class Inheritance) یا وراثت رابط (Interface Inheritance) تشکیل شود. به عنوان توضیح عامیانه، مثل این است که گفته شود «A یک موجودیت از نوع B است». به عنوان مثال، سیب یک میوه و خودرو یک وسیله نقلیه به حساب میآید. ارثبری مفهومی یک طرفه است، یعنی میتوان گفت سیب یک میوه به شمار میرود، اما نمیتوان گفت میوه یک سیب است.
پلی مورفیسم یک ویژگی برنامه نویسی شی گراست که اجازه میدهد یک وظیفه به روشهای مختلف انجام شود. به لحاظ فنی، چند ریختی در جاوا به فرد اجازه میدهد تا با تعریف یک رابط (Interface)، چندین پیاده سازی را انجام دهد.
دو نوع پلی مورفیسم در جاوا وجود دارد:
- چند ریختی زمان کامپایل (Compile Time Polymorphism)
- چند ریختی زمان اجرا (Runtime Polymorphism)
در این مقاله به مواردی از جمله دو نوع چند ریختی در جاوا یعنی چند ریختی زمان کامپایل و چند ریختی زمان اجرا، مثالهای چند ریختی در جاوا، روش اضافه بار (Overloading)، روش Overriding، دلیل استفاده از پلی مورفیسم در جاوا و بسیاری از موارد دیگر پرداخته شده است. اما در ابتدا، موضوع اصلی یعنی سوال پلی مورفیسم چیست پاسخ داده میشود.
پلی مورفیسم چیست؟
کلمه Polymorphism از ترکیب دو کلمه یونانی Poly و Morphs ایجاد شده است. پس میتوان پلی مورفیسم را به معنای «فرمهای بی شمار» در نظر گرفت. در علوم کامپیوتر پلی مورفیسم با این مفهوم ظاهر میشود که انواع مختلف از طریق یک رابط واحد قابل دسترسی هستند.
چند شکلی یکی از مهمترین ویژگیهای برنامه نویسی شی گرا به شمار میرود. در بخش بعدی این مقاله، پلی مورفیسم در جاوا به همراه مثال و انواع مختلف آن بیان میشود.
پلی مورفیسم در جاوا چیست ؟
چند ریختی در جاوا را نیز میتوان به عنوان وظیفهای تعریف کرد که میتواند یک عمل واحد را به روشهای مختلف انجام دهد. زبانهای برنامه نویسی که از چند ریختی پشتیبانی نمیکنند را نمیتوان زبانهای شی گرا نامید. اما در عوض، این زبانها به عنوان زبانهای برنامه نویسی شی محور (Object Bases Languages) شناخته میشوند. به عنوان مثال، زبان برنامه نویسی Ada نمونهای از این نوع زبانهای برنامه نویسی است. از آنجایی که جاوا از پلی مورفیسم پشتیبانی میکند، یک زبان برنامه نویسی شی گرا نامیده میشود.
پلی مورفیسم زمانی رخ میدهد که وراثت بین کلاسها وجود داشته باشد، یعنی در حالتی که کلاسهای زیادی وجود دارند که به یکدیگر مرتبط هستند. وراثت یک ویژگی قدرتمند در جاوا است و به یک کلاس اجازه میدهد تا خصوصیات و ویژگیهای کلاس دیگر را به ارث ببرد. چند شکلی در جاوا این امکان را به وجود میآورد که از این ویژگیهای ارثبری برای انجام وظایف مختلف استفاده شود. بنابراین، برای بهدست آوردن نتیجه یک وظیفه یکسان، میتوان از روشهای متنوع و گوناگونی استفاده کرد. در ادامه برای درک بهتر این موضوع به بررسی چند ریختی در زندگی روزمره پرداخته شده است.
- مقاله پیشنهادی: آموزش مقدماتی جاوا (بخش اول) — از صفر تا صد
نمونه هایی از چند ریختی در زندگی واقعی
- در زندگی واقعی یک فرد میتواند روابط گوناگونی با افراد مختلف داشته و در برابر هر فرد دیگری جایگاه متفاوتی داشته باشد. یک زن میتواند همزمان مادر، دختر، خواهر و یا دوست باشد، یعنی در برابر هر کدام از این افراد رفتار متفاوتی داشته باشد.
- بدن انسان دارای اندامهای مختلفی است و هر عضو عملکرد متفاوتی دارد. برای مثال، قلب مسئول جریان خون، ریهها برای تنفس، مغز برای فعالیتهای شناختی و کلیهها برای دفع هستند. بنابراین یک روش کارکرد استاندارد در بدن وجود دارد، که بسته به هر ارگان در بدن عملکرد متفاوتی دارد.
در بخش بعدی مثالهایی از کدهای چند شکلی در برنامه نویسی ارائه شده است.
مثال چند ریختی در جاوا
در این مثال، یک کلاس والد (Superclass) به نام «Shapes» وجود دارد که دارای متُدی به نام «()area» است. کلاس واحد «Shapes» میتواند مثلث، دایره، مستطیل و اشکال دیگری داشته باشد.
هر کلاس فرزند یا زیر کلاس (subclass) دارای روش مخصوص به خود برای محاسبه مساحت هستند که آن را در خروجی چاپ میکنند. با استفاده از وراثت و چند ریختی، کلاسهای فرزند میتوانند از متد «()area» جهت یافتن فرمول مورد نظر برای شکل خود استفاده کنند.
class Shapes {
public void area() {
System.out.println("The formula for area of ");
}
}
class Triangle extends Shapes {
public void area() {
System.out.println("Triangle is ½ * base * height ");
}
}
class Circle extends Shapes {
public void area() {
System.out.println("Circle is 3.14 * radius * radius ");
}
}
class Main {
public static void main(String[] args) {
Shapes myShape = new Shapes(); // Create a Shapes object
Shapes myTriangle = new Triangle(); // Create a Triangle object
Shapes myCircle = new Circle(); // Create a Circle object
myShape.area();
myTriangle.area();
myShape.area();
myCircle.area();
}
}
در خط هجدهم کدهای بالا، شی Shapes ساخته شده است، در خط نوزدهم این کد، شی مثلث از نوع Shapes ساخته شده و در خط بعدی آن شی دایره نیز از نوع Shapes ایجاد میشود.
خروجی کدهای مثال چند ریختی:
The formula for the area of Triangle is ½ * base * height The formula for the area of the Circle is 3.14 * radius * radius
همانطور که در کدهای فوق ملاحظه میشود، متد area در زیرکلاسهای مختلف خروجی متفاوتی دارد و بسته به اینکه شی از نوع چه زیرکلاسی باشد، فرمول مربوط به مساحت آن زیرکلاس (مثلاً مثلث یا دایره) در خروجی چاپ میشود. بنابراین، متد area دارای چندریختی است. در بخش آتی به بررسی انواع گوناگون پلی مورفیسم از جهات مختلف پرداخته شده است.
انواع پلی مورفیسم
چند ریختی در برنامه نویسی جاوا با دو روش مختلف اجرا میشود:
- روش اضافه بار (Overloading)
- روش رونویسی کردن (Overriding)
روش Overloading در جاوا چیست ؟
روش Overloading به عنوان فرآیندی تعریف میشود که میتواند چندین متد (Method) را با نام یکسان در یک کلاس ایجاد کند و هر کدام از این متدها کار متفاوتی را انجام دهند. روش Overloading زمانی اتفاق میافتد که بیش از یک متد با نام یکسان در کلاس (سوپر کلاس) وجود داشته باشد.
- مقاله پیشنهادی: متدهای جاوا — به زبان ساده
مثالی برای روش Overloading در جاوا
در مثال قبل نیز از روش Overloading استفاده شد. در این بخش نیز مثال دیگری از چند ریختی با روش Overloading ارائه شده است.
در مقایسه با مثال قبل، به جای چاپ شدن فرمول مساحت هر شکل در خروجی، متد area به گونهای تعریف شده است که با دریافت ورودی (طول، قطر و سایر موارد) امکان محاسبه مساحت را برای هر شکل خواهد داشت.
class Shapes {
public void area() {
System.out.println("Find area ");
}
public void area(int r) {
System.out.println("Circle area = "+3.14*r*r);
}
public void area(double b, double h) {
System.out.println("Triangle area="+0.5*b*h);
}
public void area(int l, int b) {
System.out.println("Rectangle area="+l*b);
}
}
class Main {
public static void main(String[] args) {
Shapes myShape = new Shapes(); // Create a Shapes object
myShape.area();
myShape.area(5);
myShape.area(6.0,1.2);
myShape.area(6,2);
}
}
خروجی کدهای فوق برای مثال روش Overloading در ادامه آمده است:
Find area Circle area = 78.5 Triangle area=3.60 Rectangle area=12
- مقاله پیشنهادی: محاسبه مساحت دایره در جاوا — به زبان ساده
روش Overriding در جاوا چیست ؟
روش Overriding فرآیندی است که در آن کلاس فرعی یا کلاس فرزند همان متدی را دارد که در کلاس والد وجود داشت.
مثالی برای روش Overriding در جاوا
در ادامه کدهای مربوط به مثال پلی مورفیسم در جاوا به روش Overriding ارائه شده است.
class Vehicle{
//defining a method
void run(){System.out.println("Vehicle is moving");}
}
//Creating a child class
class Car2 extends Vehicle{
//defining the same method as in the parent class
void run(){System.out.println("car is running safely");}
public static void main(String args[]){
Car2 obj = new Car2();//creating object
obj.run();//calling method
}
}
خروجی کدهای مثال روش Overriding در ادامه ملاحظه میشود.
Car is running safely
همچنین، چند ریختی در جاوا را میتوان از جنبه دیگری هم به دو نوع طبقهبندی کرد:
- ایستا: چند ریختی زمان کامپایل
- پویا: چند ریختی زمان اجرا
چند ریختی زمان کامپایل در جاوا چیست ؟
پلی مورفیسم زمان کامپایل در برنامه نویسی جاوا به عنوان پلی مورفیسم استاتیک یا همان ایستا نیز شناخته میشود. در روش چند ریختی زمان کامپایل، فراخوانی متد در هنگام کامپایل انجام میگیرد. چند شکلی زمان کامپایل از طریق روش Overloading ایجاد میشود، همچنین، این نوع پلی مورفیسم را میتوان از طریق عملگر Overloading نیز به دست آورد. با این حال، برنامه نویسی جاوا عملگر Overloading را پشتیبانی نمیکند.
روش Overloading زمانی انجام میشود که یک کلاس چندین متد با نام یکسان دارد، اما تعداد، نوع (Type) و ترتیب پارامترها و نوع برگشتی متدها متفاوت است. برنامه نویسی جاوا تا زمانی که بتواند نام توابع مختلف را بر اساس نوع و تعداد پارامترها تشخیص دهد به کاربر این اجازه را میدهد که از یک نام یکسان برای توابع مختلف استفاده کند.
مثالی برای پلی مورفیسم زمان کامپایل در جاوا
مثال زیر با استفاده از کلاس «Addition» و مفهوم چند شکلی زمان کامپایل با کمک «()subtract» ایجاد شده است.
package staticPolymorphism;
public class Addition
{
void sum(int a, int b)
{
int c = a+b;
System.out.println(“ Addition of two numbers :” +c); }
void sum(int a, int b, int e)
{
int c = a+b+e;
System.out.println(“ Addition of three numbers :” +c); }
public static void main(String[] args)
{
Addition obj = new Addition();
obj.sum ( 30,90);
obj.sum(45, 80, 22);
}
}
خروجی مثال پلی مورفیسم زمان کامپایل در جاوا به صورت زیر است:
Sum of two numbers: 120 Sum of three numbers: 147
در این برنامه، متد «()sum» با دو نوع پارامتر مختلف ایجاد شده است. به این ترتیب، مفهوم اساسی چند ریختی زمان کامپایل در برنامه نویسی جاوا که در آن میتوان با استفاده از چندین روش با نام یکسان، عملیات مختلفی را انجام داد در این بخش شرح داده شد.
چند ریختی زمان اجرا در جاوا چیست ؟
پلی مورفیسم زمان اجرا در جاوا با نام مقیدسازی پویا (Dynamic Binding) یا روش ارسال پویا (Dynamic Method Dispatch) نیز شناخته میشود. در این فرآیند، فراخوانی یک متد رونویسی شده، به جای زمان کامپایل در زمان اجرا به صورت پویا حل و فصل میشود. چند شکلی در زمان اجرا از طریق روش Overriding یا همان رونویسی به دست میآید.
روش Overriding زمانی انجام میشود که یک فرزند یا یک زیر کلاس متدی با نام، پارامترها و نوع بازگشتی والد یا والد یکسان داشته باشد. سپس تابعی که این مقادیر یکسان را دارد، تابع موجود در کلاس والد را رونویسی میکند. به عبارت سادهتر، اگر کلاس فرزند تعریف خود را برای متدی ارائه دهد که از پیش در کلاس والد موجود است، سپس میتوان گفت که آن تابع در کلاس مبنا (Base Class) یا والد رونویسی شده است.
- مقاله پیشنهادی: مفهوم کلاس در برنامه نویسی — همراه با نمونه مثال عملی.
لازم به ذکر است که چند شکلی زمان اجرا تنها از طریق توابع قابل دستیابی است و از طریق اعضای داده (Data Member) قابل دسترسی نیست. در برنامه نویسی شی گرا همه اعضایی (Member) که با نوع اصلی تعریف میشوند، اعضای داده به حساب میآیند.
روش Overriding با استفاده از متغیر مرجع (Reference Variable) سوپر کلاس انجام میشود. اینکه کدام متد باید فراخوانی شود، بر اساس شیای مشخص شده است که توسط متغیر مرجع به آن ارجاع داده میشود. این موضوع Upcasting به حساب میآید. Upcasting زمانی انجام میشود که متغیر مرجع کلاس والد به شی کلاس فرزند اشاره کند. برای درک بهتر موضوع، قطعه کد مثال Upcasting در ادامه آمده است.
class A{}
class B extends A{}
A a=new B(); //upcasting
در خط سوم کد، شی کلاس فرزند یعنی B به متغیر کلاس والد یعنی {}A اشاره کرده است.
- مقاله پیشنهادی: ۱۰ مفهوم اصلی زبان جاوا که هر فرد مبتدی باید بداند.
مثالهایی از چند ریختی زمان اجرا در جاوا
در این بخش از آموزش پلی مورفیسم در جاوا ، چند مثال برای درک بهتر پلی مورفیسم زمان اجرا در این زبان برنامه نویسی ارائه شده است.
مثال اول:
در این مثال، یک کلاس والد حیوان (Animal) و سه کلاس فرزند، گیاهخواران (Herbivores)، گوشتخواران (Carnivores) و همه چیزخواران (Omnivores) ایجاد شده است. کلاسهای فرزند، کلاسهای والد را بسط (Extend) میدهند و متد ()eat به آن حالت رونویسی (Override) میبخشد. فراخوانی متد ()eat با استفاده از متغیر مرجع از کلاس والد یعنی همان کلاس حیوان صورت میگیرد.
از آنجایی که متد ()eat به شی کلاس پایه اشاره دارد و متد کلاس پایه متد کلاس والد را رونویسی میکند، متد کلاس پایه در زمان اجرا فراخوانی میشود. این ماشین مجازی جاوا (Java Virtual Machine| JVM) و نه کامپایلر است که فراخوانی متد را تعیین میکند. به همین دلیل به آن پلی مورفیسم زمان اجرا گفته میشود. کدهای مربوط به مثال اول در ادامه آمده است.
class Animal{
void eat(){
System.out.println("Animals Eat");
}
}
class herbivores extends Animal{
void eat(){
System.out.println("Herbivores Eat Plants");
}
}
class omnivores extends Animal{
void eat(){
System.out.println("Omnivores Eat Plants and meat");
}
}
class carnivores extends Animal{
void eat(){
System.out.println("Carnivores Eat meat");
}
}
class main{
public static void main(String args[]){
Animal A = new Animal();
Animal h = new herbivores(); //upcasting
Animal o = new omnivores(); //upcasting
Animal c = new carnivores(); //upcasting
A.eat();
h.eat();
o.eat();
c.eat();
}
}
خروجی مثال اول چند ریختی زمان اجرا در جاوا به صورت زیر است:
Animals eat Herbivores Eat Plants Omnivores Eat Plants and meat Carnivores eat meat
مثال دوم:
در این مثال، یک کلاس والد یا همان سوپر کلاس به نام Hillstations ساخته شده است و سه زیر کلاس یا کلاس فرزند Manali ،Mussoorie و Gulmarg ایجاد شدهاند. این زیر کلاسها به کمک متدهای «()location» و «()famousfor» سوپر کلاس را گسترش (بسط) میدهند و رونویسی (Override) میکنند. متدهای «()location» و «()famousfor» به وسیله سوپر کلاس والد یعنی همان کلاس Hillstations فراخوانی میشوند.
همانطور که در ابتدای مثال دوم مقاله «پلی مورفیسم در جاوا» گفته شد، شی کلاس مبنا (Base Class) و متد کلاس مبنا، متد سوپر کلاس والد را Override (رونویسی) میکنند و در نهایت متد کلاس مبنا در زمان اجرا فراخوانی میشود. این ماشین مجازی جاوا (Java Virtual Machine| JVM) و نه کامپایلر است که فراخوانی متد را تعیین میکند. به همین دلیل به آن پلی مورفیسم زمان اجرا میگویند. کدهای مربوط به مثال دوم در ادامه آمده است:
class Animal{
void eat(){
System.out.println("Animals Eat");
}
}
class herbivores extends Animal{
void eat(){
System.out.println("Herbivores Eat Plants");
}
}
class omnivores extends Animal{
void eat(){
System.out.println("Omnivores Eat Plants and meat");
}
}
class carnivores extends Animal{
void eat(){
System.out.println("Carnivores Eat meat");
}
}
class main{
public static void main(String args[]){
Animal A = new Animal();
Animal h = new herbivores(); //upcasting
Animal o = new omnivores(); //upcasting
Animal c = new carnivores(); //upcasting
A.eat();
h.eat();
o.eat();
c.eat();
}
}
خروجی مثال دوم چند ریختی زمان اجرا در جاوا در ادامه ملاحظه میشود:
Location is: Famous for: Manali is in Himachal Pradesh It is Famous for Hadimba Temple and adventure sports Mussoorie is in Uttarakhand It is Famous for education institutions Gulmarg is in J&K It is Famous for skiing
مثال سوم:
در این مثال دو کلاس با نامهای Car و Innova ایجاد شده است. کلاس Innova کلاس Car را گسترش میدهد و به کمک متد «()run» کلاس Car را رونویسی میکند. در ادامه قطعه کد مربوط به این فرآیند مشاهده میشود.
class Car
{
void run()
{
System.out.println(“ running”);
}
}
class innova extends Car
{
void run();
{
System.out.println(“ running fast at 120km”);
}
public static void main(String args[])
{
Car c = new innova();
c.run();
}
}
خروجی برنامه بالا به صورت زیر است:
Running fast at 120 km.
میتوان مثال دیگری نیز به وسیله این کلاسها برای پلی مورفیسم در جاوا تعریف کرد. در این مثال، بررسی میشود که آیا یک چند ریختی زمان اجرا توسط اعضای داده قابل دستیابی است یا چنین نیست.
class car
{
int speedlimit = 125;
}
class innova extends car
{
int speedlimit = 135;
public static void main(String args[])
{
car obj = new innova();
System.out.println(obj.speedlimit);
}
خروجی برنامه بالا عدد ۱۲۵ است. مثال بالا به وضوح این موضوع را نشان میدهد که پلی مورفیسم زمان اجرا به وسیله اعضای داده بهدست نمیآید. به طور مختصر و ساده میتوان گفت، متدی که روش رونویسی (Override) را استفاده میکند، از اعضای داده نمیتواند استفادهای ببرد. در ادامه مقاله «پلی مورفیسم در جاوا» برای درک بهتر از پلی مورفیسم یا همان چند ریختی به بررسی مبحث چند ریختی زمان اجرا با وراثت چند سطحی همراه با مثال پرداخته شده است.
چند ریختی زمان اجرا با وراثت چند سطحی همراه با مثال
برنامه زیر مثال سادهای از روش چند ریختی زمان اجرا با وراثت چند سطحی است.
class grandfather
{
void swim()
{
System.out.println(“ Swimming”);
}
}
class father extends grandfather
{
void swim()
{
System.out.println(“ Swimming in river”);
}
}
class son extends father
{
void swim()
{
System.out.println(“ Swimming in pool”);
}
public static void main(String args[])
{
grandfather f1,f2,f3;
f1 =new grandfather();
f2 = new father();
f3 = new son();
f1.swim();
f2.swim();
f3.swim():
}
}
خروجی مثال روش چند ریختی زمان اجرا با وراثت چند سطحی به شرح زیر است:
Swimming Swimming in river Swimming in pool
مثال دیگری برای روش چند ریختی زمان اجرا با وراثت چند سطحی در ادامه آمده است:
class soundAnimal
{
public void Sound()
{
System.out.println("Different sounds of animal"); }
}
class buffalo extends soundAnimal
{
public void Sound()
{
System.out.println("The buffalo sound- gho,gho"); }
}
class snake extends soundAnimal
{
public void Sound()
{
System.out.println("The snake sound- his,his"); }
}
class tiger extends soundAnimal
{
public void Sound()
{
System.out.println("The tiger sounds- roooo, rooo"); }
}
public class Animal Main
{
public static void main(String[] args)
{
soundAnimal Animal = new soundAnimal(); soundAnimal buffalo = new buffalo();
soundAnimal snake = new snake();
soundAnimal tiger = new tiger();
Animal.Sound();
buffalo.Sound();
snake.Sound();
tiger.Sound();
}
}
خروجی مثال دوم روش چند ریختی زمان اجرا با وراثت چند سطحی به صورت زیر است:
The buffalo sound- gho,gho The snake sound- his,his The tiger sound- roooo,roooo
در بخش بعدی مقاله «پلی مورفیسم در جاوا» به زیر نوعهای (Subtypes) پلی مورفیسم پرداخته میشود.
زیر نوع های پلی مورفیسم
به طور کلی موضوع زیر نوعهای پلی مورفیسم به این معنی است که یک زیر نوع میتواند به عنوان زیر نوع نوع دیگری در برنامه باشد. برای درک بهتر این مسئله از مثالی برای زیر نوعهای پلی مورفیسم در ادامه استفاده شده است. با فرض اینکه برای این مثال باید چند شکل دلخواه ترسیم شود، میتوان کلاسی به نام «shape» را با متد «()draw» ساخت. به وسیله رونویسی متد «()draw» با زیر کلاسهای فرزند دیگر مانند دایره، مربع، مستطیل، ذوزنقه و سایر موارد، آرایهای از نوع «shape» معرفی میشود که ارجاعات ذخیره عناصر آن به ارجاعات زیر کلاس فرزند «shape» اشاره میکنند. در حین برنامه اگر بار دیگر «()draw» فراخوانی شود، تمام اشکال متد «()draw» فراخوانی خواهند شد.
به طور کلی این زیر نوع پلی مورفیسم متکی به Upcasting و مقیدسازی با تاخیر (Late Binding) است. مقیدسازی با تاخیر نام خلاصهتر مقیدسازی پویا به شمار میرود، به این دلیل که مقیدسازی پویا از سه کلمه به صورت (Dynamic Library Runtime | DLR) تشکیل میشود. به تبدیل یک نوع از دادهها به نوع دیگر (به صورت موقت) در برنامه نویسی Casting گفته میشود. گونهای از Casting که در آن سلسله مراتب وراثت از زیر نوع به سوپر نوع (Supertype) واگذار شود، Upcasting نامیده میشود. برای فراخوانی نمونه متدهای غیر نهایی، مقیدسازی با تاخیر مورد استفاده قرار میگیرد. به طور خلاصه میتوان گفت که کامپایلر نباید هیچ گونه بررسی آرگومان، بررسی نوع، فراخوانی متد و سایر موارد را انجام دهد و همه چیز را باید برای اِعمال در زمان اجرا نگه دارد. پس از ارائه مباحث نوعهای متفاوت در پلی مورفیسم، ادامه مقاله «پلی مورفیسم در جاوا» به چند سوال رایج در خصوص پلی مورفیسم در جاوا اختصاص داده شده است.
سوالات رایج پلی مورفیسم در جاوا
در این بخش به چند سوال رایج و مهم پیرامون پلی مورفیسم در جاوا پاسخ داده شده است. بهتر است ابتدا به این سوال پاسخ داده شود که پلی مورفیسم در برنامه نویسی چیست؟
پلی مورفیسم در برنامه نویسی چیست ؟
پلی مورفیسم در برنامه نویسی به این معنی است که از یک نماد واحد برای ارائه چندین نوع (Type) مختلف استفاده میشود. در بخش بعدی به بررسی متغیرهای پلی مورفیسم پرداخته شده است.
متغیرهای پلی مورفیسم کدامند ؟
متغیر پلی مورفیسم به عنوان متغیری تعریف میشود که میتواند انواع مقادیری با نوعهای مختلف را در طول مدت اجرای برنامه در خود نگهداری کند. پس از شرح متغیرهای پلی مورفیسم، شاید بهتر باشد به این موضوع هم پرداخته شود که چرا در جاوا از پلی مورفیسم استفاده میشود. بنابراین در ادامه به بررسی این موضوع پرداخته شده است.
چرا در جاوا از پلی مورفیسم استفاده میشود؟
چند شکلی در برنامه نویسی جاوا امکان نوشتن برنامهای را فراهم میکند که توانایی این را دارد تا به بهترین نحو انواع مختلفی از عملکردها که نام یکسانی دارند را در طول اجرای برنامه پردازش کنند. همچنین میتوان در برنامه نویسی جاوا با استفاده از چند شکلی در کدها به پایداری (Consistency) رسید. دانستن مزایای پلی مورفیسم کمک بسیاری در یادگیری برنامه نویسی جاوا میکند و در بخش بعدی مقاله «پلی مورفیسم در جاوا» به مزایای پلی مورفیسم در جاوا پرداخته شده است.
حال در ادامه این مقاله به شرح مزایا و نقاط مثبت پلی مورفیسم در جاوا پرداخته شده است.
مزایای پلی مورفیسم در جاوا کدامند؟
در این بخش از آموزش پلی مورفیسم در جاوا، فهرستی از برخی مزایای پلی مورفیسم در این زبان برنامه نویسی ارائه شده است:
- یکی از مزیتهای مهم پلی مورفیسم در جاوا این است که قابلیت استفاده مجدد را در کدها فراهم میکند. کلاسهایی که نوشته، تست و پیاده سازی میشوند را میتوان چندین بار مورد استفاده مجدد قرار داد. همین موضوع باعث صرفهجویی زیادی در زمان برای برنامه نویسان میشود. همچنین، کدها را میتوان بدون تأثیر بر روی کل کد اصلی تغییر داد.
- میتوان از یک متغیر برای ذخیره کردن چندین مقدار داده استفاده کرد. مقدار متغیری که از سوپر کلاس والد به زیر کلاس فرزند به ارث رسیده است را میتوان بدون تغییر مقدارش در سوپر کلاس والد یا زیر کلاسهای فرزند تغییر داد.
- با کمتر شدن خطوط کدها، اشکالزدایی کدها برای برنامه نویس آسانتر میشود.
اکنون پس از بیان مزایای پلی مورفیسم در جاوا ، در ادامه این مقاله به بررسی ویژگیهای پلی مورفیسم همراه با ارائه مثال پرداخته شده است.
ویژگیهای پلی مورفیسم در جاوا چه هستند؟
پلی مورفیسم به جز ویژگیهایی که مورد بحث قرار گرفت، مانند روش Overloading و روش Overriding، ویژگیهای بسیار دیگری نیز دارد.
برخی از این ویژگیها شامل موارد زیر میشوند:
- تبدیل خودکار نوع داده (Coercion)
- بارگذاری اضافی (Overloading) عملگر داخلی
- متغیرها یا پارامترهای پلی مورفیک
هر یک از ویژگیهای فوق در ادامه این مقاله بررسی شدهاند.
تبدیل خودکار نوع داده (Coercion)
تبدیل خودکار نوع داده با تبدیل ضمنی یک نوع شی به یک شی جدید از جهات گوناگون سر و کار دارد. تبدیل خودکار نوع داده به صورت خودکار انجام میشود تا از خطاهای نوع دادهها در کدها جلوگیری شود. بعضی از زبانهای برنامه نویسی مانند C و java از تبدیل مقدار از یک نوع داده به نوع داده دیگر پشتیبانی میکنند. این روش کاربردی تبدیل نوع دادهها دارای دو نوع ضمنی و صریح است.
تبدیل نوع داده ضمنی به صورت خودکار در برنامه نوشته شده تاثیر میگذارد، به همین دلیل، این نوع تبدیل، تبدیل خودکار نوع داده نیز به شمار میرود. برای مثال، اگر در برنامهای یک عملوند عدد صحیح وجود داشته باشد و عملوند دیگر عدد اعشاری باشد، کامپایلر به طور ضمنی مقدار عدد صحیح را به عدد اعشاری تبدیل میکند تا از خطاهای مرتبط به نوعها جلوگیری شود. برای درک بهتر این موضوع مثال زیر ارائه شده است.
class coercion {
public static void main(String[] args) {
Double area = 3.14*5*7;
System.out.println(area);
String s = "happy";
int x=5;
String word = s+x;
System.out.println(word);
}
}
خروجی مثال کدهای تبدیل خودکار نوع داده به صورت زیر بهدست میآید:
109.9 happy5
بارگذاری اضافی (Overloading) عملگر داخلی
در بارگذاری اضافی عملگر، یک عملگر یا نماد نسبت به ورودی کدها یا نوع عملوندها، رفتارهای گوناگونی از خود نشان میدهد که این موضوع یکی از ویژگیهای پلی مورفیسم ایستا است. اگرچه جاوا از بارگذاری اضافی عملگر توسط کاربر مانند ++C پشتیبانی نمیکند، اگر کاربر بتواند نحوه عملکرد یک عملگر را برای عملوندهای مختلف به خوبی تعریف کند، موارد کمی وجود دارد که جاوا به صورت داخلی به بارگذاری عملگرها بپردازد.
بارگذاری اضافی عملگر مفهومی برای استفاده از عملگرها با تصمیم خود برنامه نویس است. یک نماد عملگر یا نام متد، زمانی که در برنامه نیاز باشد، میتواند به عنوان یک نوع تعریف شده توسط کاربر مورد استفاده قرار بگیرد. به عنوان مثال، عملگر «+» هم برای انجام جمع اعدادی که نوع یکسانی دارند مورد استفاده قرار میگیرد و هم میتواند برای ادغام دو یا چند رشته استفاده شود. پس در مورد عملگر «+» میتوان گفت که برای جمع و همچنین ادغام کاربرد دارد. در ادامه، مثالی درباره بارگذاری اضافی عملگر داخلی ارائه شده است.
class coercion {
public static void main(String[] args) {
String s = "happy";
String s1 = "world";
int x=5;
int y=10;
System.out.println(s+s1);
System.out.println(x+y);
}
}
خروجی مثال فوق به صورت زیر است:
happyworld 15
به همین نحو، عملگرهایی مانند «!، &، and، |» برای عملیات منطقی و بیتی بارگذاری اضافی عملگر دارند. در هر دوی این موارد، نوع آرگومان تعیین میکند که عملگر چگونه تفسیر شود.
متغیرها یا پارامترهای پلی مورفیک
در برنامه نویسی جاوا، متغیرهای شی، نشان دهنده متغیرهای پلی مورفیک هستند. این موضوع به این دلیل است که هر متغیر شیئی از کلاس میتواند ارتباط IS-A با کلاس خودش و زیر کلاس فرزندش را داشته باشد. متغیری که بتواند مقادیر مختلف نوعها را در طول زمان اجرای کدها نگه دارد به عنوان یک متغیر چند شکلی یا پلی مورفیک تعریف میشود.
پلی مورفیسم پارامتری، مشخص میکند که در حال نوشتن رویه کلاس، نام یک فیلد میتواند با انواع مختلف نوعها و نام متد میتواند با پارامترهای گوناگون و نوعهای بازگشتی مرتبط باشد. در ادامه به مثالی در این باره پرداخته شده است.
class Shape
{
public void display()
{
System.out.println("A Shape.");
}
}
class Triangle extends Shape
{
public void display()
{
System.out.println("I am a triangle.");
}
}
class Main{
public static void main(String[] args)
{
Shape obj;
obj = new Shape();
obj.display();
obj = new Triangle();
obj.display();
}
}
خروجی مثال متغیرها یا پارامترهای پلی مورفیک به شرح زیر است:
A Shape. I am a triangle.
در این مثال، شی «obj» یک متغیر پلی مورفیک است. این موضوع به دلیل این است که همان شی سوپر کلاس به کلاس والد (Shape) و کلاس فرزند مثلث (Triangle) اشاره دارد. در ادامه این مقاله، به معایب پلی مورفیسم در جاوا پرداخته میشود.
معایب پلی مورفیسم در جاوا
با وجود تمام مزایا و ویژگیهای مثبت آن، پلی مورفیسم در جاوا کاستیهایی هم دارد.
به طور کلی این معایب را میتوان به سه دسته تقسیم کرد:
- چند شکلی در هنگام اجرا بسیار چالش برانگیز است.
- چند ریختی مقداری باعث کاهش خوانایی کدها میشود.
- پلی مورفیسم باعث بروز برخی از مشکلات عملکردی مهم در زمان واقعی میشود.
در ادامه این مقاله، دو نمونه از معایب پلی مورفیسم در جاوا بررسی شدهاند.
شناسایی نوع (Type) در طول Downcasting
Downcasting به تبدیل نوع کلاس فرزند یا یک نوع معمولی به یک نوع خاص گفته میشود. زمانی از Downcasting استفاده میشود که نیاز به دسترسی و درک رفتار زیر نوعها وجود داشته باشد.
به عنوان نمونه، در ادامه یک مثال سلسله مراتبی بسیار ساده ارائه شده است:
غذا > سبزیجات > بامیه، گوجهفرنگی
در مثال بالا گوجهفرنگی و بامیه هر دو زیر کلاس هستند. در Downcasting، نوع اشیا محدود میشوند، به این معنی که نوع معمولی به نوع خاص تبدیل میشود.
Vegetable vegetable = new Tomato(); Tomato castedTomato = (Tomato) vegetable;
در این مثال، نوع معمولی به نوع خاص تبدیل شده است. تبدیل سوپر کلاس به زیر کلاس به طور مستقیم در برنامه نویسی جاوا ممکن نیست، از این رو به طور مستقیم به کامپایلر اعلام میشود که نوع زمان اجرا شی چیست. این موضوع یکی از معایب پلی مورفیسم به حساب میآید.
مشکل کلاس پایه شکننده
مشکل کلاس پایه شکننده (Fragile Base Class) چیزی به جز یک مشکل معماری بنیادی نیست. گاهی اوقات طراحی نادرست معماری یک کلاس والد میتواند یک زیر کلاس از یک سوپر کلاس را به استفاده از سوپر کلاس به روشهای پیشبینی نشده سوق دهد. ظرافت و شکنندگی ارثبری حتی زمانی که تمام معیارها رعایت شده باشند، منجر به شکسته شدن کدها میشود. این مسئله معماری به عنوان یک مشکل کلاس پایه شکننده در سیستم برنامه نویسی شی گرا و زبان برنامه نویسی محسوب میشود. دلیل اصلی مشکل کلاس پایه شکننده این است که توسعه دهنده کلاس پایه هیچ ایدهای از طراحی زیر کلاس نداشته و هنوز هم راه حلی برای این مشکل وجود ندارد.
به این ترتیب در این مقاله سعی شد تا حد امکان به طور جامع به این سوال پاسخ داده شود که پلی مورفیسم در جاوا چیست و به مباحث پیرامون آن از جمله مفهوم، ویژگیها، مزایا و معایب پلی مورفیسم در جاوا نیز پرداخته شد.
جمعبندی
در مقاله «پلی مورفیسم در جاوا» به توضیح ابتدایی و مقدماتی پلی مورفیسم یا همان چند ریختی در جاوا و مثالهایی برای درک بهتر آن، مزایا و معایب چند ریختی، روشها و متدهای پلی مورفیسم مانند روش Overloading و روش Overriding و نوع متغیرهای این روش کاربردی پرداخته شده است.
برای بهبود روش برنامه نویسی جاوا و استفاده بهینه از متغیرها میتوان با یادگیری این روش، کدهای بهتر و خواناتری ارائه داد.