大家好,我是大鹅
今天分享一下Java这门语言,一字之差,但经常搞混的重载和重写
知识点
重写(Override)
对于父类允许访问的方法,子类都可以对其业务逻辑进行重新编写,但是名称、返回值、入参都不能改变。
这种特性,让子类可以根据自身需要,重新定义特定于自身的行为。也就是说子类可以根据自身需要重新实现父类的方法。
重写不能抛出新的异常或者当前异常的父异常类型,但是可以抛出当前异常的子类异常,例如:父类的方法申明了IOException,重写这个方法不能抛出 Exception ,因为 Exception 是 IOException 的父异常,但是可以抛出 IOException 的子类异常;
在面向对象原则里,可以重写任何现有方法。
举个重写的例子:
/** 交通工具类 */
class Vehicle{
public void move(){
System.out.print("交通工具可以移动");
}
}
/** 飞机类 */
class Aircraft extends Vehicle{
public void move(){
System.out.print("我是飞机,在天上飞的");
}
}
/** 汽车类 */
class Car extends vehicle{
public void move(){
System.out.print("我是汽车,在地上跑的");
}
}
public class TestVehicle {
public static void main(String[] args) {
Vehicle a = new Vehicle();
Vehicle b = new Aircraft();
Vehicle c = new Car();
a.move(); // 执行Vehicle类方法
b.move(); // 执行Aircraft类方法
c.move(); // 执行Car类方法
}
}
以上代码输出结果如下
交通工具可以移动
我是飞机,在天上飞的
我是起初,在地上跑的
上面的例子可以知道,尽管 b 和 c 属于 Vehicle 类型,但是运行的时候执行的是子类的move方法;
在编译阶段,会检查变量的引用类型和实际new的类型符合要求,且需要执行的方法在引用类型中存在,就可以编译通过。
在运行时,JVM(Java虚拟机)会根据实际指定的(也就是 new Class)对象类型来运行这个对象的方法。(如果指定对象中没有该方法,就调用父类的)
方法的重写规则
- 重写必须建立在继承的前提下
- 参数列表与被重写方法的参数列表必须完全相同。
- 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的子类。
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
- 声明为 final 的方法不能被重写。
- 声明为 static 的方法不能被重写,但是能够被再次声明。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 构造方法不能被重写。
super 与 this 关键字
super关键字:可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
class Vehicle{
public void move(){
System.out.print("交通工具可以移动");
}
}
class Aircraft extends Vehicle{
public void move(){
super.move();
System.out.print("我是飞机,在天上飞的");
}
}
public class TestVehicle {
public static void main(String[] args) {
Vehicle a = new Aircraft();
a.move(); // 执行Vehicle类方法
}
}
输出
交通工具可以移动
我是飞机,在天上飞的
this关键字:指向类自身对象的引用。
public class B{
private String s;
public B(String s){
this.s = s;
}
}
重载(Overload)
重载是在Java允许一个类里面,方法名称相同,返回类型可以相同也可以不同,但参数列表必须不同。
每个重载的方法或构造函数,都必须有一个独一无二的参数类型列表。
日常编程中,最常用到的地方,就是构造器的重载。
重载规则:
- 被重载的方法必须改变参数列表(参数个数或类型不一样);
- 被重载的方法可以改变返回类型;
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载;
- 无法以返回值类型作为重载函数的区分标准;
代码示例:
public class Test{
// 原始方法
public int check(){}
// 重载,参数不同
public int check(String s, Integer i){}
// 重载,参数顺序不同也可以
public int check(Integer i, String s){}
// 重载,不同的返回值
public String check(Integer i){}
// 重载,错误的示范,不能以返回值类型作为重载的区分
public Boolean check(Integer i){}
}
重写和重载的区别
区别之处 | 重载方法 | 重写方法 |
---|---|---|
参数列表 | 必须修改 | 不能修改 |
返回类型 | 可以修改 | 不能修改 |
异常 | 可以修改 | 可以使用原异常子类或删除,不能抛出新的或者更广的异常 |
访问控制符 | 可以修改 | 不能做更严格的限制,可以降低限制 例如 private 可以改成 public |
重写是子类与父类间多态性的表现,重载是一个类中方法间多态性的表现
重写是子类可以根据自身的特征,重新实现父类方法的核心业务逻辑,但是方法名称、参数列表、返回值必须和父类一致;
重载是一个类中允许定义多个方法名相同,返回值可以相同也可以不同,但参数列表必须不同的方法;
常见面试题与回答参考
说一说重载和重写的区别
重写是子类可以根据自身的特征,重新实现父类方法的业务逻辑,但是方法名称、参数列表、返回值必须和父类一致;
重载是一个类中允许定义多个方法名称相同,返回值可以相同也可以不同,但参数列表必须不同的方法;
重写是子类与父类间多态性的表现,重载是一个类中方法间多态性的表现;
构造方法能不能重写?
构造方法不能重写
因为构造方法的名称需要和类保持同名。
重写要求子类方法要和父类方法保持同名,而子类的类名和父类的类名大概率是不相同的,如果允许重写构造方法的话,那么子类中的构造方法和类名就不相同了,这和构造方法的要求是矛盾的;
构造方法能不能重载?
可以,这是重载用的最多的场景