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