شنبه ۲۹ دي ۱۴۰۳
Tut24 آموزش برنامه نویسی و مجله تخصصی فناوری ورود/عضویت

آموزش جاوا - Overriding

در فصل قبل، در مورد کلاس‌های پدر (superclass) و کلاس‌های فرزند (subclass) صحبت کردیم. اگر یک کلاس یک متد را از کلاس پدرش به ارث ببرد، امکان بازنویسی (override) آن متد وجود دارد، در صورتی که آن متد به عنوان نهایی (final) مشخص نشده باشد.

مزیت بازنویسی (overriding) این است که قابلیت تعریف رفتاری که ویژه‌ی نوع زیرکلاس است را فراهم می‌کند، یعنی یک زیرکلاس می‌تواند متد کلاس پدر را بر اساس نیاز خود پیاده‌سازی کند.

در اصطلاحات شیءگرایی، بازنویسی به معنی تغییر عملکرد یک متد موجود است.

مثال

بیایید به یک مثال نگاهی بیندازیم.


class Animal {
   public void move() {
      System.out.println("Animals can move");
   }
}

class Dog extends Animal {
   public void move() {
      System.out.println("Dogs can walk and run");
   }
}

public class TestDog {

   public static void main(String args[]) {
      Animal a = new Animal();   // Animal reference and object
      Animal b = new Dog();   // Animal reference but Dog object

      a.move();   // runs the method in Animal class
      b.move();   // runs the method in Dog class
   }
}

این عمل باعث تولید نتیجه‌ی زیر می‌شود −

خروجی


Animals can move
Dogs can walk and run

در مثال بالا، می‌توانید ببینید که اگرچه b نوعی از Animal است، اما متد move را در کلاس Dog اجرا می‌کند. دلیل این امر این است: در زمان کامپایل، بررسی بر روی نوع مرجع انجام می‌شود. با این حال، در زمان اجرا، JVM نوع شیء را تشخیص می‌دهد و متد متعلق به آن شیء را اجرا می‌کند.

بنابراین، در مثال بالا، برنامه به درستی کامپایل می‌شود زیرا کلاس Animal دارای متد move است. سپس در زمان اجرا، متد مشخص شده برای آن شیء اجرا می‌شود.

مثال زیر را در نظر بگیرید −

مثال


class Animal {
   public void move() {
      System.out.println("Animals can move");
   }
}

class Dog extends Animal {
   public void move() {
      System.out.println("Dogs can walk and run");
   }
   public void bark() {
      System.out.println("Dogs can bark");
   }
}

public class TestDog {

   public static void main(String args[]) {
      Animal a = new Animal();   // Animal reference and object
      Animal b = new Dog();   // Animal reference but Dog object

      a.move();   // runs the method in Animal class
      b.move();   // runs the method in Dog class
      b.bark();
   }
}

این عمل باعث تولید نتیجه‌ی زیر می‌شود −

خروجی


TestDog.java:26: error: cannot find symbol
      b.bark();
       ^
  symbol:   method bark()
  location: variable b of type Animal
1 error

این برنامه در زمان کامپایل خطایی را پرتاب می‌کند زیرا نوع مرجع b که Animal است، متدی به نام bark را ندارد.

قوانین بازنویسی متد (Method Overriding)

  • لیست آرگومان‌ها باید دقیقاً مشابه آرگومان‌های متد بازنویسی شده باشد.

  • نوع برگشتی باید مشابه یا یک زیرنوع از نوع برگشتی تعریف شده در متد بازنویسی شده در کلاس پدر باشد.

  • سطح دسترسی نمی‌تواند محدودتر از سطح دسترسی متد بازنویسی شده باشد. به عنوان مثال: اگر متد کلاس پدر به صورت عمومی (public) تعریف شده باشد، متد بازنویسی شده در کلاس زیرمجموعه نمی‌تواند خصوصی (private) یا محافظت‌شده (protected) باشد.

  • متد‌های نمونه (instance) تنها در صورتی قابل بازنویسی هستند که توسط زیرکلاس به ارث برده شوند.

  • متدی که به صورت نهایی (final) تعریف شده باشد نمی‌تواند بازنویسی شود.

  • متدی که به صورت استاتیک (static) تعریف شده باشد نمی‌تواند بازنویسی شود، اما می‌تواند مجدداً تعریف شود.

  • اگر یک متد قابل ارث‌بری نباشد، نمی‌تواند بازنویسی شود.

  • زیرکلاسی که در همان بسته‌ی کلاس پدر قرار دارد می‌تواند هر متدی را که به صورت خصوصی (private) یا نهایی (final) تعریف نشده باشد بازنویسی کند.

  • زیرکلاسی که در بسته‌ی دیگری قرار دارد تنها می‌تواند متد‌های غیرنهایی (non-final) که به صورت عمومی (public) یا محافظت‌شده (protected) تعریف شده‌اند را بازنویسی کند.

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

  • سازنده‌ها (constructors) قابل بازنویسی نیستند.

استفاده از کلمه کلیدی super

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

مثال


class Animal {
   public void move() {
      System.out.println("Animals can move");
   }
}

class Dog extends Animal {
   public void move() {
      super.move();   // invokes the super class method
      System.out.println("Dogs can walk and run");
   }
}

public class TestDog {

   public static void main(String args[]) {
      Animal b = new Dog();   // Animal reference but Dog object
      b.move();   // runs the method in Dog class
   }
}

این عمل باعث تولید نتیجه‌ی زیر می‌شود −

خروجی


Animals can move
Dogs can walk and run