• 【JavaSE】继承与多态(下篇)


    hello,进来的小伙伴们,你们好呐!✨

    🎁🎁系列专栏【JavaSE】

    🍰🍰本篇内容:JavaSE部分多态的知识详解,对准知识点阅读喔!

    ☕☕作者简介:一名大二即将升大三的科班小白,我很平凡,学会努力!

    🍱🍱码云存放仓库gitee:https://gitee.com/king-zhou-of-java/java-se.githttps://gitee.com/king-zhou-of-java/java-se.git

     


     一、多态的概念

    🍣🍣多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态。

    🍇🍇例1:比如打印机的功能是打印文件,那么打印机又分为彩色打印机黑白打印机

    846c970c7e7b45eca19a27587c2d65ab.jpeg

    二、多态实现条件

    🍶1. 必须在继承体系下。
    🍦2. 子类必须要对父类中方法进行重写。
    🍺3. 通过父类的引用调用重写的方法。

     🍲🍲实例:首先我们定义一个父类,这个Animal有两个成员变量,一个方法eat()。

    1. class Animal{
    2. public String name;
    3. public int age;
    4. public Animal(String name,int age){
    5. this.age = age;
    6. this.name = name;
    7. }
    8. public void eat(){
    9. System.out.println(name+"正在吃东西");
    10. }
    11. }

    🍠接下来我们定义两个子类Dog和Cat分别继承Animal,在这两个方法中重写eat()方法。

    1. class Dog extends Animal{
    2. public Dog(String name,int age){
    3. super(name,age);
    4. }
    5. public void eat(){
    6. System.out.println(name+"吃骨头");
    7. }
    8. public void bark(){
    9. System.out.println(name+"汪汪汪~");
    10. }
    11. }
    12. class Cat extends Animal{
    13. public Cat(String name,int age) {
    14. super(name,age);
    15. }
    16. public void eat(){
    17. System.out.println(name+"吃鱼");
    18. }
    19. public void mew(){
    20. System.out.println(name+"喵喵喵~");
    21. }
    22. }

    🍏再次,我们在Test函数里面定义一个静态方法func(),参数是我们的父类Animal的引用,然后我们调用这个方法eat()。

    1. public class Test1 {
    2. public static void func(Animal animal){
    3. animal.eat();
    4. }

    🍐最后我们实例化对象,初始化赋值。

    1. public static void main(String[] args) {
    2. Cat cat = new Cat("加菲猫",5);
    3. Dog dog = new Dog("旺财",6);
    4. }

    🍱🍱那么,这个时候我们就会发现一个问题,当类的调用者在编写 eat 这个方法的时候, 参数类型为 Animal (父类), 此时在该方法内部并不知道, 也不关注当前的animal 引用指向的是哪个类型(哪个子类)的实例. 此时 animal这个引用调用 eat方法可能会有多种不同的表现(和animal 引用的实例相关), 这种行为就称为 多态。🍵🍵

    三、 重写

    一、概念

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

    二、方法重写的规则

    🍏1.子类在重写父类的方法时,一般必须与父类方法原型一致: 返回值类型 方法名 (参数列表) 要完全一致。

    4c53b451b20b472383f0ba9f5ac57b9a.png

     🍧2.被重写的方法返回值类型可以不同,但是必须是具有父子关系的,比如我们将eat()方法定义成父子关系。

    5bc9d1a288034e409288c7050b756919.png

     🍰3.访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为 protected。

    7ae08e366a9b4cdfbfb4acde368a53af.png

    🍡 4.父类被static、private修饰的方法、构造方法都不能被重写。

    8d74a25e90904fc4be519434c28c3ac7.png

    🍊5.重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法构成重写。

    🍑使用方法:1.鼠标右键,找到generate.

    c7e2588fd7ea47cebc2a0bae9316df6f.png

     🍤2.选中红色箭头指向的部分。

    c72076fd6d674fcaac314dc3b72fd935.png

     🍾3.进来后点击我们要重写的方法。

    2428819f26f141fa8baeeb79f2e600d3.png

     🥞4.最后的结果就是这样。

    acb7b49add1f4837b9d0d6d54bac03b0.png

     🥯5.假如我们故意把重写的格式写错,这个注解可以很好的帮我们检测出来。

    cdfe305255404940a5ebd8acd0588c3c.png

     三、重写和重载的区别(面试题)

    4ff5cd8e1ade4047b0ee7c4945e20b47.png

     四、静态绑定

    🍼🍼概念也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载。

    🌯🌯实例:比如我们定义了一个方法func(),那么在我们的main函数中如何确定我们调用的是哪个函数呢?根据我们传入的参数即可确定。

    648e23ce6b864439a963947bf5a9b762.png

     四、向上转型和向下转型

    🍬🍬向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。
    语法格式:父类类型 对象名 = new 子类类型()

    实例:看代码。

    1. public class Test1 {
    2. public static void func(Animal animal){
    3. animal.eat();
    4. }
    5. public static void main(String[] args) {
    6. Dog dog = new Dog("旺财",6);
    7. Animal animal = dog;//animal这个引用指向了Dog对象。
    8. animal.eat();
    9. }

    这里假如我们屏蔽了Dog类中的eat()方法,我们看输出结果。

    1707b888d49143ebb4534d850857981a.png

     我们发现执行了Animalz中的eat()方法。

    那么这个时候我们Dog类中假如加入了一个color属性。

    66791c5430d24a30a3bd6be3a1d89613.png

     我们用对象animal去调用它看是否能行。

    c754395574da4de99341c29d7c97af82.png

     我们发现结果报错了,因为这个属性是Dog类中的,animal无法访问到!

    🍭🍭结论:

    向上转型的优点:让代码实现更简单灵活。
    向上转型的缺陷:不能调用到子类特有的方法。

    🥛🥛向下转型:

    🎂🎂将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。

    🍞🍞Animal向下转型为Cat,Cat本来是猫,转换为猫,安全;Animal向下转型为Dog,Cat本来是猫,转换为狗,不安全!

    1. public class Test1 {
    2. public static void func(Animal animal){
    3. animal.eat();
    4. }
    5. public static void main(String[] args) {
    6. Dog dog = new Dog("旺财",6);
    7. Animal animal = dog;//animal这个引用指向了Dog对象。
    8. Cat cat = new Cat("咪咪",7);
    9. cat = (Cat) animal;
    10. cat.mew();
    11. }

    🥃🥃程序可以通过编程,但运行时抛出异常---因为:animal实际指向的是狗。
    现在要强制还原为猫,无法正常还原,运行时抛出:ClassCastException(类型转换异常)

    14486e4923114eef98a8ae03bc01e399.png

    💊💊解决方案:
    Java中引进了 instanceof ,如果该表达式为true,则可以安全转换。

    1. if(animal instanceof Cat){
    2. cat = (Cat) animal;
    3. cat.mew();
    4. }
    5. if(animal instanceof Dog){
    6. dog = (Dog) animal;
    7. dog.bark();
    8. }

    🍎🍎运行结果: f265d124e08d44cf95dd11da04bc915a.png

  • 相关阅读:
    c++ SFML ftp删除文件
    CRC原理介绍及STM32 CRC外设的使用
    框架学习1:Spring常见问题
    使用国内源加速pip安装包
    WebView2 通过 PuppeteerSharp 实现爬取 王者 壁纸 (案例版)
    ABP框架之——数据访问基础架构(下)
    量化投资学习——商品期货研究(一)
    Vue 设置v-html中元素样式
    LRU缓存机制
    Java学习苦旅(十五)——异常
  • 原文地址:https://blog.csdn.net/m0_62426532/article/details/126474148