Java - 重写


在上一章中,我们讨论了超类和子类。如果一个类从其超类继承了一个方法,那么只要该方法未标记为final,就有机会重写该方法。

重写的好处是:能够定义特定于子类类型的Behave,这意味着子类可以根据其要求实现父类方法。

在面向对象术语中,覆盖意味着覆盖现有方法的功能。

例子

让我们看一个例子。

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 的一种类型,它也运行 Dog 类中的 move 方法。原因是:在编译时,对引用类型进行检查。然而,在运行时,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 的方法。

方法重写规则

  • 参数列表应该与重写方法的参数列表完全相同。

  • 返回类型应该与超类中原始重写方法中声明的返回类型相同或其子类型。

  • 访问级别不能比被重写方法的访问级别更严格。例如:如果超类方法声明为 public,则子类中的重写方法不能为 private 或 protected。

  • 实例方法只有被子类继承时才可以被重写。

  • 声明为final的方法不能被覆盖。

  • 声明为静态的方法不能被重写,但可以重新声明。

  • 如果一个方法不能被继承,那么它就不能被覆盖。

  • 与实例的超类位于同一包中的子类可以重写任何未声明为 private 或 Final 的超类方法。

  • 不同包中的子类只能重写声明为 public 或 protected 的非最终方法。

  • 重写方法可以抛出任何未检查异常,无论被重写方法是否抛出异常。但是,重写方法不应抛出新的或比被重写方法声明的异常更广泛的已检查异常。重写方法可以抛出比被重写方法更窄或更少的异常。

  • 构造函数不能被重写。

使用 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