• 【Java初阶】面向对象三大特性之多态


    🎈🎈 作者: whispar
    🎈🎈 专栏 :Java由浅入深

    🌈刷题,面试,求职,快来牛客网一起成为offer收割机!🌈

    快来注册一起成为offer收割机!!

    d924065539c14401af169e0db320941a.png


    目录

    一、方法的重写

    二、向上转型和向下转型

    三、多态的优缺点


    一、方法的重写

    重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!

    1. class Animal{
    2.    public int size;
    3.    public String color;
    4.     public Animal(int size, String color) {
    5.         this.size = size;
    6.         this.color = color;
    7.     }
    8.     public void move(){
    9.         System.out.println("此动物正在移动");
    10.     }
    11. }
    12. class Dog extends Animal{
    13.    public String name;
    14.    public int age;
    15.     public Dog(int size, String color, String name, int age) {
    16.         super(size, color);
    17.         this.name = name;
    18.         this.age = age;
    19.     }
    20.     //子类对父类方法进行重写
    21.     @Override
    22.     public void move() {
    23.         System.out.println("正在快速移动");
    24.     }
    25. }

    方法重写的规则

    • 子类在重写父类方法时,一般必须与父类方法原型一致:返回值类型 方法名(参数列表)要完全一致,使用@Override注解来进行合法性检验

    • 被重写的方法的返回值一般要相同

    • 重写之后的方法,访问权限不能比父类中被重写的方法的访问权限更低

      ✅方法重写与重载的区别?

      区别点重写(override)重载(override)
      参数列表一定不能修改必须修改
      返回类型一定不能修改【除非可以构成父子类关系】可以修改
      访问限定符一定不能做更严格的限制(可以降低限制)可以修改
      方法名称必须相同必须相同

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

    5a8b066d43456d9ceb79aa20ba449881.png

    二、向上转型和向下转型

    • 向上转型

    1. class Fruit{
    2.    public void show() {
    3.        System.out.println("this is a fruit");
    4.   }
    5. }
    6. class Apple extends Fruit{
    7.    @Override
    8.    public void show() {
    9.        System.out.println("this is a apple");
    10.   }
    11.    public void test() {
    12.        System.out.println("i am a apple");
    13.   }
    14. }
    15. public class TestDemo {
    16.     public static void main(String[] args) {
    17.         //向上转型
    18.         //实例化Apple类,并新建一个Fruit类的引用变量引用该实例,调用实例的show()方法
    19.         Fruit fruit = new Apple();
    20.         fruit.show();
    21.     }
    22. }

    f127ff0a03ef93cb3bcd39fffec166e1.png

    调用实例的test()方法

    fruit.test();

    47662077d83b6ecc66459319e684677e.png

    分析:

    向上转型即使用父类的引用变量去引用子类的实例,当向上转型之后,父类引用变量可以访问子类中属于父类的属性和方法,但是不能访问子类独有的属性和方法

    例子中由于子类重写了父类的show()方法,所以调用的show()方法是子类的show()方法,输出结果为:“this is a apple”,而调用子类的test()方法则会报错

    下面代码中一个引用调用一个方法,因为这个引用所引用的对象不一样,导致调用的这个方法,所表现的行为不一样,这种思想就叫做多态

    1. class Fruit{
    2.   public void show() {
    3.       System.out.println("this is a fruit");
    4.   }
    5. }
    6. class Orange extends Fruit{
    7.   @Override
    8.   public void show(){
    9.       System.out.println("this is a C");
    10.   }
    11. }
    12. class Apple extends Fruit{
    13.   @Override
    14.   public void show() {
    15.       System.out.println("this is a apple");
    16.   }
    17.   public void test() {
    18.       System.out.println("i am a apple");
    19.   }
    20. }
    21. public class TestDemo {
    22.     public static void main(String[] args) {
    23.         Apple apple = new Apple();
    24.         Orange orange = new Orange();
    25.         func(apple);
    26.         func(orange);
    27.     }
    28.     //方法传参
    29.     public static void func(Fruit fruit){
    30.         fruit.show();
    31.     }
    32.     //方法返回
    33.     public static Fruit func2(){
    34.         return new Apple();
    35.     }
    36. }
    1. public class TestDemo {
    2.     public static void main(String[] args) {
    3.          Fruit fruit = new Apple();
    4.          Apple apple = (Apple)fruit;
    5.          fruit.show();
    6.     }
    7. }

    上述代码是允许的,因为fruit引用的对象原本就是Apple对象向上转型得到的,在对fruit向下转型后得到的还是Apple类的对象,能够被Apple类的引用变量引用。

    实例化Apple类,并新建一个Fruit类的引用变量“fruit”引用该实例,然后新建一个Orange类的引用变量,引用向下转型的“fruit”变量,代码如下:

    1. Fruit fruit = new Apple();
    2. Orange orange = (Orange) fruit;

    上述代码虽然能够编译成功,但是在运行的时候会报错,因为fruit对象是由Apple对象向上转型得到的,只能够向下转型成Apple对象,不能够向下转型成Orange对象。

    798be416be9fef1eba767c433f54a123.png

    向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换

    1. public class TestDemo {
    2.     public static void main(String[] args) {
    3.         Fruit fruit = new Apple();
    4.         if(fruit instanceof Apple){
    5.              Apple apple = (Apple)fruit;
    6.         }
    7.          fruit.show();
    8. }

    三、多态的优缺点

    • 提高了代码的可维护性,主要体现在每一个派生类编写功能调用,只需要对抽象基类进行处理即可。

    • 提高了代码的可扩展性,主要体现在派生类的功能可以被基类的方法或引用变量所调用。

    避免在构造方法中调用重写的方法

    1. class B {
    2.    public B() {
    3.        func();
    4.   }
    5.    public void func() {
    6.        System.out.println("B.func()");
    7.   }
    8. }
    9. class D extends B {
    10.    private int num = 1;
    11.    @Override
    12.    public void func() {
    13.        System.out.println("D.func() " + num);
    14.   }
    15. }
    16. public class TestDemo2{
    17.    public static void main(String[] args) {
    18.        D d = new D();
    19.   }
    20. }

    b2f46ad0a268841ce76b04632cf08b90.png

    【说明】

    • 构造D对象的同时,会调用B的构造方法;

    • B的构造方法中调用了 func方法,此时会触发 动态绑定,会调用到D中的 func,并且由于没有初始化num,所以num = 0.

      💖如果文章对你有帮助,请多多点赞、收藏、评论、关注支持!!💖 

    ced485cbb11e458d81a746890b32cf3f.gif

     

  • 相关阅读:
    侯捷 - C++ Startup 揭密:C++ 程序的生前和死后 (一)
    day31 文件上传&js验证&mime&user.ini&语言特性
    petite-vue源码剖析-为什么要读源码?
    SpringBoot学习笔记(项目创建,yaml,多环境开发,整合mybatis SMM)
    PMD 6.47.0 发布,代码分析器
    基础测试干了4年,自学了自动化(太片面),突然接到被裁员消息
    计算机毕业设计Java校园考勤系统(系统+源码+mysql数据库+lw文档)
    人工神经网络的应用实例,神经网络简单应用实例
    机器学习实验六:决策树-海洋生物例子
    【课程】SP Module2 辅音和元音的声学
  • 原文地址:https://blog.csdn.net/m0_56361048/article/details/126679604