javaSE中多态

javaSE中多态

我们要了解多态就要先知道什么是向上转型

1、向上转型
向上转型发生的时机:
1、直接赋值
在这里插入图片描述
2、父类引用作为函数参数
在这里插入图片描述
3、作为函数的返回值
在这里插入图片描述
2、动态绑定

在这里插入图片描述
这是为什么呢???
父类引用调用的eat方法不应该是调用父类的eat方法吗??
这是因为这时候发生了动态绑定。

那什么是动态绑定呢???
动态绑定:
1、父类引用 引用子类对象
2、父类引用调用父类和子类同名的覆盖方法

同名的覆盖方法(重写)只发生在父子类关系中:
1、方法名相同
2、参数列表相同(参数个数,类型)
3、返回值相同(特殊情况:返回值不同(也叫协变类型))
重写的时候 需要注意的:
在这里插入图片描述
关于重写时需要注意
1. 重写和重载完全不一样. 不要混淆(思考一下, 重载的规则是啥?)
2. 普通方法可以重写, static 修饰的静态方法不能重写.
3. 重写中子类的方法的访问权限不能低于父类的方法访问权限.
4. 重写的方法返回值类型不一定和父类的方法相同(但是建议最好写成相同, 特殊情况除外).

在这里插入图片描述
动态绑定也叫运行时绑定
找到代码所在的路径www这个文件夹里
在这里插入图片描述
按住shift键+右键,点击在此处打开powershell窗口
输入 javap -c Test1 回车,找到mian函数
在这里插入图片描述
Animal.eat() 这时候编译的时候是调用父类的方法,为什么是运行是调用子类的方法呢?
因为这时在 编译的时候不能够确定调用的是谁的方法,只有在运行的时候才能够确定。
这就叫运行时绑定也叫动态绑定

动态绑定
在这里插入图片描述
重写当中的协变类型
在这里插入图片描述
重载会发生静态绑定 也叫 编译时绑定
在这里插入图片描述

2.1、通过父类引用只能访问自己的成员
在这里插入图片描述
2.2、重载和重写的区别
在这里插入图片描述
2.3、向下转型
在这里插入图片描述
在这里插入图片描述
这就发生了向下转型
但是这样不好
Animal是动物,bird是鸟
Bird bird = (Bird)animal; 所有的动物都是鸟吗?肯定不是嘛,这里也可以理解是大范围强制转换为 小范围

看下面:animal引用Dog
然而Bird bird = (Bird)animal;
通过bird就不能调用fly这个方法,
在这里插入图片描述
通过bird就不能调用fly这个方法,这里就要判断一下
instanceof 可以判定一个引用是否是某个类的实例
在这里插入图片描述
向下转型不安全,不建议使用
在父类的构造方法中调用重写方法的时候 是一个坑
在这里插入图片描述

2.4、理解多态
有了上面的向上转型, 动态绑定, 方法重写之后, 我们就可以使用 多态(polypeptide) 的形式来设计程序了

比如说:
在这里插入图片描述
通过shape同一个引用,可以表现出多种形态
实现多态的前提:动态绑定

	当类的调用者在编写 drawMap 这个方法的时候, 参数类型为 Shape (父类), 此时在该方法内部并不知道, 也不关注当

前的 shape 引用指向的是哪个类型(哪个子类)的实例. 此时 shape 这个引用调用 draw 方法可能会有多种不同的表现
(和 shape 对应的实例相关), 这种行为就称为 多态

使用多态的好处是什么?
1) 类调用者对类的使用成本进一步降低.
封装 是让类的调用者不需要知道类的实现细节
多态 能让类的调用者连这个类的类型是什么都不必知道,,只需要知道这个对象具有某个方法即可,因此,,多态可以理解成是封装的更进一步, 让类调用者对类的使用成本进一步降低

作用1:能够降低代码的 “圈复杂度”, 避免使用大量的 if - else
例如我们现在需要打印的不是一个形状了, 而是多个形状. 如果不基于多态, 实现代码如下

class Shape {
    public void draw() {
        System.out.println("draw()::");
    }
}

class Yuan extends Shape{
    @Override
    public void draw() {
        System.out.println("●");
    }
}
class Sanj extends Shape{
    @Override
    public void draw() {
        System.out.println("△");
    }
}
public class TestD {

    public static void main(String[] args) {
        Yuan yuan = new Yuan();
        Sanj sanj = new Sanj();
        String[] str = {"yuan","sanj","yuan","sanj","yuan"};

        for (String a : str) {
            if(a.equals("yuan")){
                yuan.draw();
            }else if (a.equals("sanj")){
                sanj.draw();
            }
        }
    }
 }

在这里插入图片描述
那我们就可以简化代码:

class Shape {
    public void draw() {
        System.out.println("draw()::");
    }
}

class Yuan extends Shape{
    @Override
    public void draw() {
        System.out.println("●");
    }
}
class Sanj extends Shape{
    @Override
    public void draw() {
        System.out.println("△");
    }
}
public class TestD {

    public static void main(String[] args) {
        Yuan yuan = new Yuan();
        Sanj sanj = new Sanj();
        Shape[] shapes = {yuan,yuan,sanj,sanj,yuan};

        for (Shape shape : shapes) {
            shape.draw();
        }
    }
}

在这里插入图片描述

总结
1、多态是面向对象程序设计中比较难理解的部分. 我们会在后面的抽象类和接口中进一步体会多态的使用. 重点是多态带来的编码上的好处.
另一方面, 如果抛开 Java, 多态其实是一个更广泛的概念, 和 “继承” 这样的语法并没有必然的联系.
2、C++ 中的 “动态多态” 和 Java 的多态类似. 但是 C++ 还有一种 “静态多态”(模板), 就和继承体系没有关系了.
3、Python 中的多态体现的是 “鸭子类型”, 也和继承体系没有关系./
4、Go 语言中没有 “继承” 这样的概念, 同样也能表示多态.
无论是哪种编程语言, 多态的核心都是让调用者不必关注对象的具体类型. 这是降低用户使用成本的一种重要方式

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Später321

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值