متد instance در زیرکلاسی که همان signature (نام به همراه تعداد و نوع پارامترها) و همان نوع بازگشتی را به عنوان متد instance در فوقکلاس داشته باشد، متد فوقکلاس را بازنویسی (Override) میکند.
قابلیت بازنویسی متد توسط زیرکلاس به یک کلاس اجازه میدهد از فوقکلاسی که رفتارش «به اندازه کافی نزدیک» است ارث ببرد و سپس رفتار را بر اساس نیاز خود تغییر دهد. متد بازنویسیشده باید نام، تعداد و نوع پارامترها و نوع بازگشتی یکسانی با متدی که آن را بازنویسی میکند داشته باشد. متد بازنویسیشده همچنین میتواند نوع بازگشتی زیرمجموعهای از نوع متد بازنویسیشده برگرداند. به این نوع بازگشتی، Covariant Return Type گفته میشود.
هنگام بازنویسی یک متد، ممکن است بخواهید از Annotation به نام @Override استفاده کنید که به کامپایلر دستور میدهد شما قصد بازنویسی متدی در فوقکلاس را دارید. اگر به هر دلیلی کامپایلر تشخیص دهد متدی با آن signature در یکی از فوقکلاسها وجود ندارد، خطایی تولید خواهد کرد. برای اطلاعات بیشتر درباره @Override، بخش Annotations را ببینید.
اگر زیرکلاس متد static با همان signature متد static موجود در فوقکلاس تعریف کند، متد زیرکلاس آن را مخفی (Hide) میکند.
تفاوت بین مخفی کردن متد static و بازنویسی متد instance پیامدهای مهمی دارد:
Animal است که یک متد instance و یک متد static دارد:public class Animal {
public static void testClassMethod() {
IO.println("The static method in Animal");
}
public void testInstanceMethod() {
IO.println("The instance method in Animal");
}
}
کلاس دوم، زیرکلاسی از Animal به نام Cat:
public class Cat extends Animal {
public static void testClassMethod() {
IO.println("The static method in Cat");
}
public void testInstanceMethod() {
IO.println("The instance method in Cat");
}
public static void main(String[] args) {
Cat myCat = new Cat();
Animal myAnimal = myCat;
Animal.testClassMethod();
myAnimal.testInstanceMethod();
}
}
کلاس Cat متد instance موجود در Animal را بازنویسی و متد static موجود در Animal را مخفی میکند. متد main این کلاس یک نمونه از Cat ایجاد و testClassMethod را روی کلاس و testInstanceMethod را روی نمونه فراخوانی میکند.
خروجی این برنامه به این صورت است:
The static method in Animal
The instance method in Cat
همانطور که قول داده شده بود، نسخهی متد static مخفیشدهای که فراخوانی شد از فوقکلاس و نسخهی متد instance بازنویسیشدهای که فراخوانی شد از زیرکلاس بود.
---Default Methodها و Abstract Methodها در Interfaceها مثل متدهای Instance به ارث میرسند. اما وقتی فوقنوعهای یک کلاس یا Interface چندین Default Method با signature یکسان فراهم کنند، کامپایلر جاوا از قوانین ارثبری برای حل تداخل نام استفاده میکند. این قوانین بر اساس دو اصل زیر عمل میکنند:
کلاسها و Interfaceهای زیر را در نظر بگیرید:
public class Horse {
public String identifyMyself() {
return "I am a horse.";
}
}
public interface Flyer {
default public String identifyMyself() {
return "I am able to fly.";
}
}
public interface Mythical {
default public String identifyMyself() {
return "I am a mythical creature.";
}
}
public class Pegasus extends Horse implements Flyer, Mythical {
public static void main(String... args) {
Pegasus myApp = new Pegasus();
IO.println(myApp.identifyMyself());
}
}
متد Pegasus.identifyMyself() رشتهی I am a horse را برمیگرداند.
Interfaceها و کلاسهای زیر را در نظر بگیرید:
public interface Animal {
default public String identifyMyself() {
return "I am an animal.";
}
}
public interface EggLayer extends Animal {
default public String identifyMyself() {
return "I am able to lay eggs.";
}
}
public interface FireBreather extends Animal { }
public class Dragon implements EggLayer, FireBreather {
public static void main (String... args) {
Dragon myApp = new Dragon();
IO.println(myApp.identifyMyself());
}
}
متد Dragon.identifyMyself() رشتهی I am able to lay eggs را برمیگرداند.
اگر دو یا چند Default Method که بهطور مستقل تعریف شدهاند با هم تداخل داشته باشند، یا یک Default Method با یک Abstract Method تداخل داشته باشد، کامپایلر جاوا خطای کامپایل تولید میکند. باید صریحاً متدهای فوقنوع را بازنویسی کنید.
مثال ماشینهای کنترلشده با کامپیوتر که حالا پرواز هم میکنند را در نظر بگیرید. دو Interface (OperateCar و FlyCar) پیادهسازی پیشفرضی برای یک متد یکسان (startEngine()) فراهم میکنند:
public interface OperateCar {
// ...
default public int startEngine(EncryptedKey key) {
// Implementation
}
}
public interface FlyCar {
// ...
default public int startEngine(EncryptedKey key) {
// Implementation
}
}
کلاسی که هر دو OperateCar و FlyCar را پیادهسازی میکند، باید متد startEngine() را بازنویسی کند. میتوانید هر کدام از پیادهسازیهای پیشفرض را با کلمهکلیدی super فراخوانی کنید.
public class FlyingCar implements OperateCar, FlyCar {
// ...
public int startEngine(EncryptedKey key) {
FlyCar.super.startEngine(key);
OperateCar.super.startEngine(key);
}
}
نامی که قبل از super میآید (در این مثال FlyCar یا OperateCar) باید به یک Super-Interface مستقیم ارجاع دهد که متد فراخوانیشده را تعریف یا به ارث برده باشد. این شکل فراخوانی متد فقط به تفکیک بین Interfaceهای مختلفی که Default Methodهایی با signature یکسان دارند محدود نمیشود. میتوانید از کلمهکلیدی super برای فراخوانی Default Method در کلاسها و Interfaceها استفاده کنید.
متدهای Instance به ارثرسیده از کلاسها میتوانند Abstract Methodهای Interface را بازنویسی کنند. Interfaceها و کلاسهای زیر را در نظر بگیرید:
public interface Mammal {
String identifyMyself();
}
public class Horse {
public String identifyMyself() {
return "I am a horse.";
}
}
public class Mustang extends Horse implements Mammal {
public static void main(String... args) {
Mustang myApp = new Mustang();
IO.println(myApp.identifyMyself());
}
}
متد Mustang.identifyMyself() رشتهی I am a horse را برمیگرداند. کلاس Mustang متد identifyMyself() را از کلاس Horse به ارث میبرد که متد انتزاعی همنام موجود در Interface Mammal را بازنویسی میکند.
---نکته: متدهای static در Interfaceها هرگز به ارث نمیرسند.
ویرایشگر دسترسی یک متد بازنویسیشده میتواند دسترسی بیشتر، اما نه کمتر، نسبت به متد بازنویسیشده داشته باشد. مثلاً یک متد instance با ویرایشگر protected در فوقکلاس میتواند در زیرکلاس public شود اما نه private.
اگر سعی کنید یک متد instance در فوقکلاس را به متد static در زیرکلاس تبدیل کنید، و بالعکس، خطای زمان کامپایل دریافت خواهید کرد.
---جدول زیر خلاصهی آنچه هنگام تعریف متدی با signature یکسان با متد موجود در فوقکلاس رخ میدهد را نشان میدهد.
| متد Instance فوقکلاس | متد Static فوقکلاس | |
|---|---|---|
| متد Instance زیرکلاس | بازنویسی (Override) | خطای زمان کامپایل |
| متد Static زیرکلاس | خطای زمان کامپایل | مخفی کردن (Hide) |
نکته: در زیرکلاس میتوانید متدهای به ارثرسیده از فوقکلاس را Overload کنید. چنین متدهای Overload شدهای نه مخفی میکنند و نه بازنویسی میکنند — متدهای جدیدی هستند که منحصراً به زیرکلاس تعلق دارند.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/