Java 重写
在上一章中,我们讨论了超类和子类。如果一个类从其超类继承一个方法,那么就有机会覆盖该方法,前提是它没有被标记为final。
覆盖的好处是:能够定义一个与子类类型特定的行为,这意味着子类可以根据自己的需求实现父类方法。
在面向对象的术语中,覆盖意味着覆盖现有方法的功能。
示例
让我们来看一个示例。
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的方法不能被重写。
 - 
声明为static的方法不能被重写,但可以重新声明。
 - 
如果一个方法不能被继承,则它也不能被重写。
 - 
在同一包中的子类可以重写任何非private或final的父类方法。
 - 
在不同包中的子类只能重写父类中声明为public或protected的非final方法。
 - 
重写方法可以抛出任何未检查异常,而不管被重写方法是否抛出异常。然而,重写方法不应抛出已被重写方法声明的新的或更宽的已检查异常。重写方法可以抛出比被重写方法更窄或更少的异常。
 - 
构造方法不能被重写。
 
使用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
极客教程