前言:
在上一篇【Java】还不理解继承?一篇文章看懂继承|继承入门我们很好的了解、学习了继承的基础知识和细节。我们讲到继承的其中一个特性就是:子类继承父类,可以重写从父类继承过来的实例方法。
那么,到底什么是重写、又该如何重写、重写的细节、具体意义、功能等等,将在此篇着重展开.
【Tips】:重写是建立在继承基础之上。子类继承了父类的非static和static属性以及方法,但是只能重写从父类继承过来的实例方法。静态属性、静态方法和非静态的属性都可以被继承和隐藏(hide),而不能够被重写!(关于隐藏,我们后期再讲)
目录
前言:Part1:基本介绍Part2:重写的意义/功能2.1:访问方法(动态绑定)2.2:直接意义: Part3:重写的细节&注意事项Part4:总结:重写&重载对比
Part1:基本介绍
方法重写(Override),又叫方法覆盖。是指子类继承了父类非private方法,若在子类中再次声明&定义一个方法名、方法参数、返回类型和父类一样的方法时,我们就称:子类重写/覆盖/覆写/Override了父类的这个方法。
eg:
public class Animal { private int age; private String name; public void eat() { System.out.println("吃东西ing"); } //下面是两个属性的构造器 public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
public class Cat extends Animal { @Override public void eat() { System.out.println("吃小鱼儿ing"); } public void climb(){ System.out.println("猫咪爬树");}
可以看到:Cat类有两个方法:
eat():此方法是在继承父类方法的基础上,重写父类的eat()方法climb():此方法是Cat类自己单独声明&实现的,与父类无任何关系重写好处:
从子类的视角来看:重写可以满足在子类继承父类方法的同时,但又不受父类的方法实现的严格限制,同时拥有自己特有的方法实现!两全其美(比如eat都是吃,每个动物都有这个行为,但是吃的具体食物不同,所以实际的方法实现并不同)。
对重写的理解:
更通俗来说,当子类继承父类时,你觉得父类的方法不能满足需求,就重写一下(当然你也可以不重写,这完全取决于子类.这点是和抽象类以及接口不同的地方)。
在Java和其他一些高级面向对象的编程语言中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。 如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
Part2:重写的意义/功能
关于重写的好处、理解,我们心里都有数了。那么,重写给我们带来了什么呢?
2.1:访问方法(动态绑定)
提到重写,就肯定会提到动态绑定,它们两个是分不开的。
我们先来谈谈对重写和动态绑定的理解:
重写:方法重写,是Java在语法层次上的规则。动态绑定:方法重写这个语法规则的底层实现(动态绑定机制:调用对象方法,方法会与运行类型绑定,调用属性与编译类型有关)总之,重写和动态绑定本质相同,侧重点不同。这里我们着重谈谈语法层次上的重写(动态绑定会在后期讲解继承背后的原理中着重介绍)
首先,我们要清楚继承的本质是:查找关系。即:子类对象访问属性/方法时,会逐级向上查找,直到找到合适的属性/方法,则访问/调用。
当父类引用指向子类对象时,用父类引用去调用父类中方法时,是这样的流程:(这里还是以上面代码举例)
类之间的关系: 父类引用指向子类对象,调用方法时的流程:Animal animal01 = new Cat();animal01.eat();
【重写功能】:父类引用指向子类对象,父类引用调用方法时,若方法被重写,会优先调用子类重写方法!
综上可以看出多态+重写+继承(重写就是建立在继承之上的)的语法规则,带来了非常明显的一个好处:方便管理子类对象(只需要知道对象的父类型,不用一个个去搞清楚运行类型,再根据运行类型调用其方法)
为什么这么说呢:
public class Main { public static void main(String[] args) { Animal animal01 = new Cat(); Animal animal02 = new Dog(); Animal[] animals = {animal01, animal02}; for (Animal animal : animals) { animal.eat(); } }}
2.2:直接意义:
增强类(指父类)的重用性、复用性、扩展性
Part3:重写的细节&注意事项
子类方法重写父类,必须保证子类方法的权限大于父类的权限or和父类权限相同(private < 默认(不写)< protected < public),才可以覆盖理解
:保证重写之后一定会优先调用到子类的方法,如果缩小访问权限继承就没有意义。(继承的本质就是查找关系,优先使用子类)不能用静态覆盖非静态,静态只能覆盖静态:如果父类中方法是不是static,那么子类覆盖父类时不能将被覆盖的方法写出static子类重写方法的返回值与父类完全一致或者是父类方法返回值的子类方法签名必须完全一致(方法签名=方法名+参数列表)子类异常不能大于父类异常 Part4:总结:重写&重载对比
关于重载,已在【Java】保姆级讲解|从0到1学会方法及方法重载 ( 入门,包懂)详细解释。这里我们将它们进行对比。
区别点 | 重写(Override) | 重载(Overload) |
---|---|---|
概念 | 方法名相同,参数列表不同(参数类型、参数个数) | 返回类型、方法名、参数列表相同 |
发生范围 | 父子类(不一定是直接父类) | 本类 |
访问修饰符 | 子类重写方法的访问权限必须大于or等于父类方法的权限 | 无要求 |
本质 | 利用栈结构,实现方法覆盖(后进,先出) | 同名方法,不同访问(由编译器指定,自动匹配) |
Java岛冒险记【从小白到大佬之路】
LeetCode每日一题–进击大厂算法