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引用和Animal对象
        Animal b = new Dog();   //Animal引用和Dog对象

        a.move();   //运行Animal类中的方法
        b.move();   //在Dog类中运行方法
    }
}

这将产生以下结果:

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 b = new Dog();   //动物参考但Dog对象

        a.move();   //运行Animal类中的方法
        b.move();   //在Dog类中运行方法
        b.bark();
    }
}

这将产生以下结果:

TestDog.java声明为static的方法不能被重写,但可以重新声明。 error: cannot find symbol
        b.bark();
       ^
  symbol:   method bark()
  location: variable b of type Animal
1 error

由于b的类型Animal没有bark方法,因此该程序将引发编译时错误。

方法重写规则


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

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

  • 访问级别不能比重写方法的访问级别更严格。例如:如果将父类方法声明为public,则子类中的重写方法不能是私有的或受保护的;

  • 实例方法只有在子类继承的情况下才能被重写;

  • 声明为final的方法不能被重写;

  • 声明为static的方法不能被重写,但可以重新声明;

  • 如果无法继承方法,则无法重写该方法;

  • 与实例的父类在同一包中的子类可以重写未声明为私有或最终的任何父类方法;

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

  • 无论重写方法是否引发异常,重写方法都可以引发任何uncheck异常。但是,重载方法不应引发比被重载方法声明的异常新的或更广泛的检查异常。与重写方法相比,重写方法可以引发更窄或更少的异常;

  • 构造函数不能被重写。

使用super关键字


调用重写方法的父类版本时,需要使用super关键字。

class Animal {
    public void move() {
        System.out.println("Animals can move");
    }
}

class Dog extends Animal {
    public void move() {
        super.move();   //调用父类方法
        System.out.println("Dogs can walk and run");
    }
}

public class TestDog {

    public static void main(String args[]) {
        Animal b = new Dog();   //动物参考但Dog对象
        b.move();   //在Dog类中运行方法
    }
}

这将产生以下结果:

Animals can move
Dogs can walk and run