• 【Java】多态


    目录

    概念

    示例代码:

    运行结果:

    多态的访问特点

    示例代码:

    多态的优缺点

    示例代码:

    多态的转型

    示例代码:


    概念

    多态 是面向对象三大特征之一。

    同一个对象,在不同的时刻表现出来的不同形态。

    举例:狗

    狗就是狗        狗 dog = new 狗();

    我们也可以说 动物 animal = new 狗();

    这里狗在不同的时刻表现出来的形态,这就是多态。

    多态的前提和体现

    1. 有继承 / 实现关系
    2. 方法重写
    3. 有父类引用指向子类对象

    示例代码

    AnimalParent.java

    1. package com.面向对象.Demo22;
    2. public class AnimalParent {
    3. // 父类
    4. public void eat(){
    5. System.out.println("这是动物类 都有eat 方法");
    6. }
    7. }

    Dog.java

    1. package com.面向对象.Demo22;
    2. public class Dog extends AnimalParent {
    3. // 子类
    4. /**
    5. * 多态的基本的条件
    6. * 1.有继承 或 实现(后面会学习到接口的概念)的关系
    7. * 2.方法的重写——子类重写父类的方法
    8. * 3.有父类的引用指向子类
    9. */
    10. @Override
    11. public void eat() {
    12. System.out.println("子类(狗类)重写了父类 eat 方法");
    13. }
    14. }

    AnimalDemo.java

    1. package com.面向对象.Demo22;
    2. public class AnimalDemo {
    3. public static void main(String[] args) {
    4. // 本身的类型指向引用 new 本身的对象
    5. Dog dog = new Dog();
    6. dog.eat();
    7. // 有父类的引用指向子类对象 多态
    8. AnimalParent animalParent = new Dog();
    9. animalParent.eat();
    10. }
    11. }

    运行结果:


    多态的访问特点

    • 成员变量:编译看左边,执行看左边;
    • 成员方法:编译看左边,执行看右边。

    为什么成员变量和成员方法的访问不一样呢?

    ∵ 成员方法有重写,而成员变量是没有的。

    示例代码:

    AnimalParent.java

    1. package com.面向对象.Demo22;
    2. public class AnimalParent {
    3. public int age = 20;
    4. // 父类
    5. public void eat() {
    6. System.out.println("这是动物类 都有eat 方法");
    7. }
    8. }

    Dog.java

    1. package com.面向对象.Demo22;
    2. public class Dog extends AnimalParent {
    3. public int age = 10;
    4. public int weight = 20;
    5. // 子类
    6. /**
    7. * 多态的基本的条件
    8. * 1.有继承 或 实现(后面会学习到接口的概念)的关系
    9. * 2.方法的重写——子类重写父类的方法
    10. * 3.有父类的引用指向子类
    11. */
    12. @Override
    13. public void eat() {
    14. System.out.println("子类(狗类)重写了父类 eat 方法");
    15. }
    16. public void show(){}
    17. }

    AnimalDemo.java

    1. package com.面向对象.Demo22;
    2. public class AnimalDemo {
    3. /**
    4. * AnimalParent animalParent = new Dog();
    5. * 成员属性 编译阶段是看左边(父类animalParent)执行也是看左边(父类animalParent);
    6. * 成员方法 编译阶段是看左边(父类animalParent)执行是看右边(子类Dog);
    7. * @param args
    8. */
    9. public static void main(String[] args) {
    10. /**
    11. * 本身的类型指向引用 new 本身的对象
    12. * 非多态
    13. */
    14. Dog dog = new Dog();
    15. dog.eat();
    16. System.out.println(dog.age);
    17. System.out.println(dog.weight);
    18. /**
    19. * 有父类的引用指向子类对象
    20. * 多态
    21. */
    22. AnimalParent animalParent = new Dog();
    23. animalParent.eat();
    24. System.out.println(animalParent.age);//20,这个age 是父类animalParent里的 age
    25. // System.out.println(animalParent.weight);//报错,Cannot resolve symbol 'weight'(无法解析weight)
    26. //成员属性 编译阶段是看左边(父类animalParent),父类没有这个属性,所以报错
    27. // animalParent.show();//报错,Cannot resolve method 'show' in 'AnimalParent'
    28. // 成员方法 编译阶段是看左边(父类animalParent),父类没有show这个方法,所以报错,
    29. //执行虽然看的右边 子类有show(),但是这个show()没有重写父类的show()
    30. // (父类没有show())所以,在编译阶段都报错,何谈执行阶段
    31. animalParent.eat(); // 输出:子类(狗类)重写了父类 eat 方法
    32. //父类和子类都有eat()方法,但是 执行是看右边的(子类Dog)里的eat()
    33. // Ctrl + Alt + 鼠标点击eat,可以看到都有那些类里面有eat()方法
    34. }
    35. }

    多态的优缺点

    • 多态的好处:提高了程序的扩展性
    • 具体体现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作
    • 多态的弊端:不能使用子类的特有功能

    示例代码:

    AnimalParent.java

    1. package com.面向对象.Demo23;
    2. public class AnimalParent { //显示AnimalParent的类图关系,Ctrl+Alt+点击AnimalParent
    3. public void eat(){
    4. System.out.println("父类-AnimalParent-eat()");
    5. }
    6. }

    Cat.java

    1. package com.面向对象.Demo23;
    2. public class Cat extends AnimalParent{
    3. @Override
    4. public void eat() {
    5. System.out.println("子类-Cat-eat()");
    6. }
    7. }

    Dog.java

    1. package com.面向对象.Demo23;
    2. public class Dog extends AnimalParent {
    3. @Override
    4. public void eat() {
    5. System.out.println("子类-Dog-eat()");
    6. }
    7. }

    AnimalOperate.java

    1. package com.面向对象.Demo23;
    2. // 动物操作类 操作 狗和猫类
    3. public class AnimalOperate {
    4. /**
    5. * 1.方法1
    6. * 方法传递参数 猫类 调用 猫类的 eat 方法
    7. */
    8. // public void userCatEat(Cat cat) {
    9. // cat.eat();
    10. // }
    11. // public void userDogEat(Dog dog) {
    12. // dog.eat();
    13. // }
    14. /**
    15. * 2.方法2
    16. */
    17. // public void userAnimal(){
    18. // 多态的访问特点 编译看左边 执行看右边
    19. // AnimalParent cat = new Cat();
    20. // cat.eat();
    21. // Dog dog = new Dog();
    22. // AnimalParent dog = new Dog();
    23. // dog.eat();
    24. //
    25. // }
    26. // 上面的两部分代码冗余 优化为下面代码
    27. /**
    28. * 3.方法3————多态
    29. * 该方法 传递的类型 是子类 但是该方法接受的参数 是父类型
    30. * animalOperate.userAnimal(new Dog());
    31. * 后面如果 在增加子类,这个方法就不用去动了,只需要写增加的子类里面的方法即可
    32. */
    33. public void userAnimal(AnimalParent animalParent) {
    34. /**
    35. * 调用animalOperate.userAnimal(new Dog());这个方法,传递的是子类 new Dog(),
    36. * 就<=> animalParent = new Dog();
    37. */
    38. // animalParent = new Dog(); 既然等价,可以省略
    39. // 成员方法 编译看左边 执行看右边,编译:父类中有eat(),执行:调用的Dog()下的eat()
    40. animalParent.eat();
    41. }
    42. /**
    43. * 多态机制 优缺点
    44. * 优点:提高程序的扩展性
    45. * 缺点:不能使用子类的特有功能
    46. */
    47. }

    AnimalDemo.java

    1. package com.面向对象.Demo23;
    2. public class AnimalDemo {
    3. public static void main(String[] args) {
    4. // 1. new 动物操作类
    5. AnimalOperate animalOperate = new AnimalOperate();
    6. // 2. 调用猫类中的 Eat()
    7. // animalOperate.userCatEat(new Cat()); //子类-Cat-eat() //使用每个子类都创建一个方法,扩展性差
    8. // 3. 调用狗类中的 Eat()
    9. // animalOperate.userDogEat(new Dog()); //子类-Dog-eat() //使用每个子类都创建一个方法,扩展性差
    10. /**
    11. * 因此使用下面的多态机制
    12. * 传递的类型 是子类 但是该方法接受的参数 是父类型
    13. */
    14. animalOperate.userAnimal(new Cat()); //子类-Cat-eat()
    15. animalOperate.userAnimal(new Dog()); //子类-Dog-eat()
    16. }
    17. }

    多态的转型

    1. 向上转型 (多态机制)

            从子到父

            父类引用指向子类对象

    2. 向下转型 (强转)

            从父到子(可能发生类型转换异常java.lang.ClassCastException)

            父类引用转为子类对象

    示例代码:

    Dog.java

    1. package com.面向对象.Demo23;
    2. public class Dog extends AnimalParent {
    3. @Override
    4. public void eat() {
    5. System.out.println("子类-Dog-eat()");
    6. }
    7. public void showDog(){
    8. System.out.println("Dog-Dog类中独有的方法");
    9. }
    10. }

    AnimalDemo02.java

    1. package com.面向对象.Demo23;
    2. public class AnimalDemo02 {
    3. public static void main(String[] args) {
    4. // 多态中 调用成员方法 编译阶段是看左边
    5. Dog dog = new Dog();
    6. System.out.println("直接 通过 dog 类型接收");
    7. dog.showDog();
    8. //多态中 编译阶段是看左边 执行是看右边 向上转型 从子到父
    9. AnimalParent parent = new Dog();
    10. // parent.showDog(); //报错,父类没有showDog()
    11. parent.eat(); // 向上转型 从子到父
    12. // 访问 parent 对象中 showDog() 向下转型 从父到子
    13. System.out.println("通过 向下转型");
    14. Dog dog1 = (Dog) parent; //这里为什么可以转,∵父类本身就是Dog()
    15. dog1.showDog();
    16. // 将父转换成子———— 运行时 编译阶段程序不报错,∵ 程序不清楚这里的parent是 cat 还是 dog
    17. Cat cat = (Cat) parent; // 将parent(Dog) 强转 Cat 报错
    18. // 异常 ,java.lang.ClassCastException 类型转换异常
    19. //是否可以直接将dog1 强转 cat ?
    20. // Cat cat1 = (Cat) dog1; //报错,∵ 在17行已经明确的将 父类parent 转为 dog1
    21. }
    22. }

    下一篇文章:抽象类

  • 相关阅读:
    Mybatis主配置—Configuration
    【论文笔记16】NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis
    神经网络基础部件-卷积层详解
    前端系列-1 HTML+JS+CSS基础
    MySQL高阶语句(二)
    【无标题】算法不能盲目刷!!算法修炼手册(持续更新)
    Python梯度提升决策树的方法示例
    WPF向Avalonia迁移(四、其他事项)
    iOS hitTest 机制用处之二-----使用pointInside方法
    深度学习网络模型 MobileNet系列MobileNet V1、MobileNet V2、MobileNet V3网络详解以及pytorch代码复现
  • 原文地址:https://blog.csdn.net/qq_57268251/article/details/133546526