banner
lMingyul

lMingyul

记录穿过自己的万物
jike

重载与重写

记录一下自己在学习 Java 的一些笔记。

重载#

重载: 重载指的是方法的重载,重载的特征就是两个或多个方法具有同名。

经典的重载方法#

重载多用于构造器方法,因为构造器作用是初始化构建对象的,构造器的名字必须与类名相同,这就形成经典的无参构造器与有参构造器这一对重载方法。

下面给出了示例:

/**
 * @author mingyu
 */
public class User {

    private Integer id;

    private String userName;
		
  	//  无参构造器
    public User() {
    }
		
  	// 单个参数的构造器
    public User(Integer id) {
        this.id = id;
    }

  	// 全参构造器
    public User(Integer id, String userName) {
        this.id = id;
        this.userName = userName;
    }

}

为什么需要重载#

我们都知道,Java 中最重要的一个概念就是:对象。那方法就是对象的一个个行为。一个对象在做相同名字的行为也可以是在做不同的事情,比如:小明打麻将。

字面意思:小明在和其他人一起玩麻将这类娱乐活动

其他意思:小明在 "打" 一个名字叫 "麻将" 的人

所以说,现实生活中语言当中的歧义也会出现在代码里。

还比如说,一个人在吃东西,我给他什么,他就在吃什么,我给他面条,他的行为就是吃苗条,我给他米饭,他就是在吃米饭,但是他的行为都叫吃东西

总结:重载在代码当中是很必要的。

重载的区分#

如果不同的方法都是一个名字,要怎么分辨它们呢?

分辨重载的重要原则:每个重载的方法必须有独一无二的参数类型列表(即每个方法都有与其他同名方法不同的入参)

那不同的参数列表,到底哪里不同呢?

参数类型的不同#

public class Test {

    public static void main(String[] args) {
      	// age 的类型不同可以区分两个同名的方法
        getPerson("mingyu", 18);
        getPerson("mingyu", "18");
    }

    static void getPerson(String name, int age) {
        System.out.println("name: " + name + ", " + "int_age: " + age);
    }

    static void getPerson(String name, String age) {
        System.out.println("name: " + name + ", " + "String_age: " + age);
    }

}

输出结果:

name: mingyu, int_age: 18
name: mingyu, String_age: 18

参数顺序的不同#

虽然参数顺序不同可以区分同名的重载方法,但是不推荐使用这种使用方式进行区分,因为这样写代码很难维护

public class Test {

    public static void main(String[] args) {
        getPerson("mingyu", 18);
        getPerson(18,"mingyu");
    }

    static void getPerson(String name, int age) {
        System.out.println("name: " + name + ", " + "behind_age: " + age);
    }

    static void getPerson(int age, String name) {
        System.out.println("name: " + name + ", " + "first_age: " + age);
    }

}

输出结果:

name: mingyu, behind_age: 18
name: mingyu, first_age: 18

返回值区分重载方法#

除了参数列表的类型、顺序可以区分方法外,我们能否用方法的返回值来区分呢?

答案是不行的,下面给出了例子。

 void f() {}
    
 int f() { return 1; }

当我们只想调用 f() 方法,但不需要该方法的返回值(如 System.out.println 方法),这时如果只是调用方法 f(),Java 是无法区分我们需要调用的是哪个方法的。

基本类型的重载#

对于只有基本类型不同的重载方法,会出现基本类型可以从小类型自动提升到较大类型的情况

public class Test {

    public static void main(String[] args) {
        int x = 5;
        checkBasicTypes(x);
    }

    static void checkBasicTypes(long x) {
        System.out.println("Type long: " + x);
    }

    static void checkBasicTypes(float x) {
        System.out.println("Type float: " + x);
    }

    static void checkBasicTypes(double x) {
        System.out.println("Type double: " + x);
    }

}

输出结果:

Type long: 5

变量 x 为 int 类型,但是 checkBasicTypes() 方法并没有 int 类型的入参,当程序运行时,会找到类型比 int 类型大的方法进行调用,即传入数据类型小于方法的参数类型,传入的数据类型会自动被提升。( int -> long)

重写#

重写一般出现在父子类关系之间,父类与子类有两个名称与参数列表都相同的方法,由于它们具有相同的方法名称,所以在方法调用的时候,子类的方法会覆盖同名的父类方法。

下面是重写的一个例子

public class Test {

    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.say();
    }
}

class Animal {
    public void say() {
        System.out.println("I'm animal.");
    }
}

class Dog extends Animal {

    @Override
    public void say() {
        System.out.println("I'm Dog.");
    }

    public void eat() {
        System.out.println("Dog like eat meat.");
    }
}

输出结果:

I'm Dog.

上面的例子中,父类与子类都定义了 say() 方法,实际上称之为子类重写了父类的 say()方法。

重写方法之后,当我们调用子类对象的 say() 方法,尽管 Dog 对象的类型是 Animal ,Java 依然会调用 Dog 的 say() 方法,因为子类的方法会覆盖同名的父类方法。

重写的原则#

如果需要重写方法,需要满足里式替换原则:

  • 子类方法的访问权限必须大于等于父类方法
    • 如父类方法修饰符为 protected,那子类方法的修饰符只能是 protected 或 public
  • 子类方法的返回类型必须是父类方法返回类型或为其子类型。
    • 如 B extends A : 父方法返回类型为 A,那么子类方法可以返回 A 类型,也可以是 B 类型
  • 子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型。

@Override 注解#

@Override 注解并不是 Java 中的关键字,但可以当做关键字一样使用,如果在重写方法上加上这个注解,编译器就会帮助你检查是否满足上面的三个限制条件,检测这个重写方法是否合法。有时候还可以有效的防止意外重载。

参考资料#

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。