📜  Java-覆盖

📅  最后修改于: 2020-11-15 04:27:06             🧑  作者: Mango


在上一章中,我们讨论了超类和子类。如果一个类从其超类继承了一个方法,则只要未将其标记为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没有树皮名称的方法。

方法覆盖规则

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

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

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

  • 实例方法只有在子类继承的情况下才能被覆盖。

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

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

  • 如果无法继承方法,则无法覆盖该方法。

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

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

  • 无论重写方法是否引发异常,重写方法都可以引发任何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