【Java面向对象】5-3 方法重写
§5-3 方法重写
类的继承关系使得子类能够继承父类的方法。本节将主要讨论方法重写。
5-3.1 方法重写
方法重载是指在同一类中方法名和方法的返回值相同情况下,构造形参列表不同的方法。与方法重载不同,方法重写是在具有继承关系的类中,方法返回值类型、方法名、形参列表都相同的情况下,对某一类中的方法的重构。一个最明显的区别是,重载在同一类中发生,而重写发生在具有继承关系的不同类之中,且重写的方法访问权限相同。
5-3.1.1 静态方法重写
首先我们先看看静态方法重写。
//Root.java
public class Root {
public static void test() {
System.out.println("执行Root --> test()");
}
}
//Branch.java
public class Branch extends Root {
public static void test() {
System.out.println("执行Branch --> test()");
}
}
在主方法中调用:
//Application.java
public class Application {
public static void main(String[] args) {
//静态方法重写
Branch branch = new Branch();
branch.test(); //新建子类对象,并调用其静态方法。
Root root = new Branch(); //在父类新建子类对象,父类引用指向子类对象,子类继承,向上传递
root.test();
}
}
编译后运行,得到结果:
执行Branch --> test()
执行Root --> test()
可见,若都为静态方法,则无论创建对象时调用的是谁的构造器(创建谁的对象),重写后调用时只与所属类有关。这在一定程度上说明,静态方法是随着类加载的,是类的方法。
这样看来,方法重写对于静态方法而言没有意义,因为静态方法随着类一同载入方法区中。因此,我们讨论的方法重写都是针对于非静态方法。
5-3.1.2 非静态方法重写
倘若我们把上述方法都改为非静态方法:
//Root.java
public class Root {
public void test() {
System.out.println("执行Root --> test()");
}
}
//Branch.java
public class Branch extends Root {
@Override //注解(带有功能)
public void test() {
System.out.println("执行Branch --> test()");
}
}
再次编译运行,则得到结果:
执行Branch --> test()
执行Branch --> test()
可见,这时都调用了子类的方法。这也说明,非静态方法存在于对象中,是对象的方法。调用方法时,和对象有关。为了方法的可用性(在外部使用),方法的重写针对的是被 public
修饰的方法。
IDEA 快捷键:按下组合键 Alt + Insert
,选择 重写方法(Override)
。
5-3.1.3 注意点
有关方法的重写,需要明确的是:
- 重写发生在具有继承关系的类中,且必须是子类重写父类的方法;
- 方法名、参数列表、返回值类型必须相同;
- 重写的方法修饰符范围可以扩大,但不可以缩小;
- 抛出的异常范围可以被缩小,但不可以扩大;
- 由
final
修饰的方法不可以被重写;
那么,我们何时需要方法重写呢?
我们以[5-4 继承](5 - 4 继承.md)中的例子来看:
//Creature.java
public class Creature {
String name = "生物"; //成员变量初始化
public Creature() {
System.out.println("已调用父类构造器。")
}
public String getName() {
return name; //若只进行了初始化,那么将默认输出:生物
}
public void setName(String newName) {
this.name = newName;
}
}
//Animal.java
public class Animal extends Creature {
String name = "动物";
public Animal() {
super(); //super关键字,将在下文中提到
System.out.println("已调用子类构造器。")
}
//子类缺省父类的 getName() 和 setName() 方法
}
若没有在子类中重写父类的 getName()
和 setName()
方法,那么在主方法中无参创建子类的对象后,调用 getName()
方法,会发现并没有输出 动物
,而是 生物
。因此,当父类的方法子类不一定需要,或子类所需条件父类不一定满足时,往往需要方法重写。