Java - 覆盖

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

覆盖的好处是:能够定义一个行为特定于子类类型,这意味着子类可以根据其需求实现父类方法.

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

示例

让我们看一个例子.

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会计算出对象类型并运行属于该特定对象的方法.

因此,在上面的示例中,程序将自动类编译以来有方法移动.然后,在运行时,它运行特定于该对象的方法.

考虑以下示例 :

示例

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没有树皮名称的方法.

方法覆盖规则

  • 参数列表应与重写方法完全相同.

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

  • 访问级别不能比覆盖方法的访问级别.例如:如果超类方法被声明为public,则子类中的重写方法不能是私有的或受保护的.

  • 只有在实例方法中才能覆盖实例方法它们由子类继承.

  • 无法覆盖声明为final的方法.

  • 声明为static的方法无法重写,但可以重新声明.

  • 如果某个方法无法继承,则无法覆盖该方法.

  • 与实例的超类在同一个包中的子类可以覆盖任何未声明为私有或最终的超类方法.

  • 另一个包中的子类只能覆盖声明为public或protected的非final方法.

  • 重写方法可以抛出任何uncheck异常,无论被覆盖的方法是否抛出异常.但是,重写方法不应抛出新的或更宽的已检查异常,而不是被重写方法声明的异常.覆盖方法可以抛出比重写方法更窄或更少的异常.

  • 无法覆盖构造函数.

使用超级关键字

当调用重写方法的超类版本时,使用 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