重载和重写傻傻分不清楚?看这一篇就够了

66 阅读6分钟

大家好,我是大鹅

今天分享一下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

重写是子类与父类间多态性的表现,重载是一个类中方法间多态性的表现

重写是子类可以根据自身的特征,重新实现父类方法的核心业务逻辑,但是方法名称、参数列表、返回值必须和父类一致;

重载是一个类中允许定义多个方法名相同,返回值可以相同也可以不同,但参数列表必须不同的方法;

常见面试题与回答参考

说一说重载和重写的区别

重写是子类可以根据自身的特征,重新实现父类方法的业务逻辑,但是方法名称、参数列表、返回值必须和父类一致;

重载是一个类中允许定义多个方法名称相同,返回值可以相同也可以不同,但参数列表必须不同的方法;

重写是子类与父类间多态性的表现,重载是一个类中方法间多态性的表现

构造方法能不能重写?

构造方法不能重写

因为构造方法的名称需要和类保持同名。

重写要求子类方法要和父类方法保持同名,而子类的类名和父类的类名大概率是不相同的,如果允许重写构造方法的话,那么子类中的构造方法和类名就不相同了,这和构造方法的要求是矛盾的;

构造方法能不能重载?

可以,这是重载用的最多的场景