Java 简明教程

Java - Overriding

在上一章中,我们讨论了超类和子类。如果一个类从其超类继承了一个方法,那么就有机会覆盖该方法,前提是它没有被标记为 final。

Benefit of Overriding in Java

重写的优点是:能够定义特定于子类类型的一种行为,这意味着子类可以根据其需求实现父类方法。

object-oriented 术语中,重写是指重写现有 method 的功能。

Java Method Overriding

Method overriding 使我们能够实现运行时 polymorphism ,用于编写超类中已定义的子类方法的特定定义。

超类方法和在子类中覆盖的方法应该具有相同的声明签名,例如参数列表、类型和返回类型。

Usage of Java Method Overriding

以下是方法覆盖在 Java 中的两种重要用法:

  1. 方法重写用于实现运行时多态。

  2. 重写方法用于编写子类方法的特定定义(该方法称为被重写方法)。

Example of Method Overriding in Java

我们来看一个示例。

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 方法。然后,在运行时,运行特定于该对象的方法。

考虑以下示例 −

Example

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 的方法。

Rules for Method Overriding

  1. 参数列表应与被覆盖方法的参数列表完全相同。

  2. 返回类型应相同,或为超类中原始重写方法中声明的返回类型的子类型。

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

  4. 只有当实例方法被子类继承时,才能覆盖它们。

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

  6. 声明为 static 的方法不能被覆盖,但可以重新声明。

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

  8. 与实例超类的包相同的子类可以覆盖未声明为 private 或 final 的任何超类方法。

  9. 不同包中的子类只能覆盖声明为 public 或 protected 的非 final 方法。

  10. 覆盖方法可以抛出任何未选中异常,无论被覆盖方法是否抛出异常。但是,覆盖方法不应抛出比被覆盖方法声明的异常更新的或更广泛的已选中异常。覆盖方法可以抛出比被覆盖方法更窄或更少异常。

  11. Constructors cannot be overridden.

Java Method and Constructor Overriding

在 Java 中,每个类都有不同的名称,且构造函数的名称与类名称相同。因此,我们无法重写 constructor ,因为它们不能具有相同的名称。

Java Method Overriding: Using the super Keyword

当调用一个被覆盖方法的超类版本时,使用 super 关键字。

Example: Using the super Keyword

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