🎈🎈 作者: whispar
🎈🎈 专栏 :Java由浅入深🌈刷题,面试,求职,快来牛客网一起成为offer收割机!🌈

目录
重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
- class Animal{
- public int size;
- public String color;
-
- public Animal(int size, String color) {
- this.size = size;
- this.color = color;
- }
- public void move(){
- System.out.println("此动物正在移动");
- }
- }
- class Dog extends Animal{
- public String name;
- public int age;
-
- public Dog(int size, String color, String name, int age) {
- super(size, color);
- this.name = name;
- this.age = age;
- }
- //子类对父类方法进行重写
- @Override
- public void move() {
- System.out.println("正在快速移动");
- }
- }
方法重写的规则
子类在重写父类方法时,一般必须与父类方法原型一致:返回值类型 方法名(参数列表)要完全一致,使用@Override注解来进行合法性检验
被重写的方法的返回值一般要相同
重写之后的方法,访问权限不能比父类中被重写的方法的访问权限更低
✅方法重写与重载的区别?
| 区别点 | 重写(override) | 重载(override) |
|---|---|---|
| 参数列表 | 一定不能修改 | 必须修改 |
| 返回类型 | 一定不能修改【除非可以构成父子类关系】 | 可以修改 |
| 访问限定符 | 一定不能做更严格的限制(可以降低限制) | 可以修改 |
| 方法名称 | 必须相同 | 必须相同 |
方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现

向上转型
- class Fruit{
- public void show() {
- System.out.println("this is a fruit");
- }
- }
- class Apple extends Fruit{
- @Override
- public void show() {
- System.out.println("this is a apple");
- }
- public void test() {
- System.out.println("i am a apple");
- }
- }
- public class TestDemo {
- public static void main(String[] args) {
- //向上转型
- //实例化Apple类,并新建一个Fruit类的引用变量引用该实例,调用实例的show()方法
- Fruit fruit = new Apple();
- fruit.show();
- }
- }

调用实例的test()方法
fruit.test();

分析:
向上转型即使用父类的引用变量去引用子类的实例,当向上转型之后,父类引用变量可以访问子类中属于父类的属性和方法,但是不能访问子类独有的属性和方法。
例子中由于子类重写了父类的show()方法,所以调用的show()方法是子类的show()方法,输出结果为:“this is a apple”,而调用子类的test()方法则会报错
下面代码中一个引用调用一个方法,因为这个引用所引用的对象不一样,导致调用的这个方法,所表现的行为不一样,这种思想就叫做多态。
- class Fruit{
- public void show() {
- System.out.println("this is a fruit");
- }
- }
- class Orange extends Fruit{
- @Override
- public void show(){
- System.out.println("this is a C");
- }
- }
-
- class Apple extends Fruit{
- @Override
- public void show() {
- System.out.println("this is a apple");
- }
- public void test() {
- System.out.println("i am a apple");
- }
- }
- public class TestDemo {
- public static void main(String[] args) {
- Apple apple = new Apple();
- Orange orange = new Orange();
- func(apple);
- func(orange);
- }
- //方法传参
- public static void func(Fruit fruit){
- fruit.show();
- }
- //方法返回
- public static Fruit func2(){
- return new Apple();
- }
- }
- public class TestDemo {
- public static void main(String[] args) {
- Fruit fruit = new Apple();
- Apple apple = (Apple)fruit;
- fruit.show();
- }
- }
上述代码是允许的,因为fruit引用的对象原本就是Apple对象向上转型得到的,在对fruit向下转型后得到的还是Apple类的对象,能够被Apple类的引用变量引用。
实例化Apple类,并新建一个Fruit类的引用变量“fruit”引用该实例,然后新建一个Orange类的引用变量,引用向下转型的“fruit”变量,代码如下:
- Fruit fruit = new Apple();
- Orange orange = (Orange) fruit;
上述代码虽然能够编译成功,但是在运行的时候会报错,因为fruit对象是由Apple对象向上转型得到的,只能够向下转型成Apple对象,不能够向下转型成Orange对象。

向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换
- public class TestDemo {
- public static void main(String[] args) {
- Fruit fruit = new Apple();
- if(fruit instanceof Apple){
- Apple apple = (Apple)fruit;
- }
- fruit.show();
- }
提高了代码的可维护性,主要体现在每一个派生类编写功能调用,只需要对抽象基类进行处理即可。
提高了代码的可扩展性,主要体现在派生类的功能可以被基类的方法或引用变量所调用。
❗避免在构造方法中调用重写的方法
- class B {
- public B() {
- func();
- }
- public void func() {
- System.out.println("B.func()");
- }
- }
- class D extends B {
- private int num = 1;
- @Override
- public void func() {
- System.out.println("D.func() " + num);
- }
- }
- public class TestDemo2{
- public static void main(String[] args) {
- D d = new D();
- }
- }

【说明】
构造D对象的同时,会调用B的构造方法;
B的构造方法中调用了 func方法,此时会触发 动态绑定,会调用到D中的 func,并且由于没有初始化num,所以num = 0.
💖如果文章对你有帮助,请多多点赞、收藏、评论、关注支持!!💖
