多态---相关操作

為{幸葍}努か 提交于 2019-12-02 09:20:00

多态—相关操作

  1. 基本格式与使用

    • Zi类

      package cn.xiaoge.day10.demo04;
      
      public class Zi extends Fu {
      
          @Override
          public void method() {
              System.out.println("子类方法");
          }
      }
      
    • Fu类

      package cn.xiaoge.day10.demo04;
      
      public class Fu {
      
          public void method() {
              System.out.println("父类方法");
          }
      
          public void methodFu() {
              System.out.println("父类特有方法");
          }
      
      }
      
    • 执行路口

      package cn.xiaoge.day10.demo04;
      
      /*
      代码当中体现多态性, 其实就是一句话: 父类引用指向子类对象.
      
      格式:
      父类名称 对象名 = new 子类名称();
      或者:
      接口名称 对象名 = new 实现类名称();
      
       */
      
      public class Demo01Multi {
      
          public static void main(String[] args) {
              // 使用多态的写法
              // 左侧父类的引用, 指向了右侧子类的对象
              Fu obj = new Zi();
      
              obj.method(); // 子类方法
              obj.methodFu();
          }
      
      }
      
      // 运行结果
      子类方法
      父类特有方法
      
  2. 访问成员变量的两种方式

    • Zi类

      package cn.xiaoge.day10.demo05;
      
      public class Zi extends Fu {
      
          int num = 20;
      
          int age = 16;
      
          @Override
          public void showNum(){
              System.out.println(num);
          }
      
          @Override
          public void method() {
              System.out.println("子类方法");
          }
      
          public void methodZi() {
              System.out.println("子类特有方法");
          }
      
      }
      
    • Fu类

      package cn.xiaoge.day10.demo05;
      
      public class Fu {
      
          int num = 10;
      
          public void showNum() {
              System.out.println(num);
          }
      
          public void method() {
              System.out.println("父类方法");
          }
      
          public void methodFu() {
              System.out.println("父类特有方法");
          }
      
      }
      
    • 执行路口

      package cn.xiaoge.day10.demo05;
      
      /*
      访问成员变量的两种方式:
      
      1. 直接通过对象名称访问成员变量: 看等号左边是谁, 优先用谁, 没有则向上找.
      2. 间接通过成员方法访问成员变量: 看该方法属于谁, 优先用谁, 没有则向上找.
       */
      
      public class Demo01MultiField {
      
          public static void main(String[] args) {
              // 使用多态的写法, 父类的引用指向子类对象
              Fu obj = new Zi();
      
              System.out.println(obj.num); // 父: 10
              // System.out.println(obj.age); // 错误写法 父类里没有成员变量age
              System.out.println("===================");
      
              // 子类没有覆盖重写, 就是父: 10
              // 子类如果覆盖重写, 就是子: 20
              obj.showNum();
      
          }
      
      }
      
      // 运行结果
      10
      ===================
      20
      
    • 执行路口

      package cn.xiaoge.day10.demo05;
      
      /*
      在多态的代码当中, 成员方法的访问规则是:
          看new的是谁, 就优先用谁, 没有则向上找
      
      口诀: 编译看左边, 运行看右边.
      
      对比一下:
      成员变量, 编译看左边, 运行还看左边.
      成员方法: 编译看左边, 运行看右边.
       */
      
      public class Demo02MultiMethod {
      
          public static void main(String[] args) {
              Fu obj = new Zi(); // 多态
      
              obj.method(); // 父子都有, 优先用子
              obj.methodFu(); // 子类没有, 父类有, 向上找到父类
      
              // 编译看左边, 左边是Fu, Fu当中没有method方法, 所以编译报错.
              // obj.methodZi();
          }
      
      }
      
      // 运行结果
      子类方法
      父类特有方法
      
  3. 向上转型和向下转型

    • Animal类

      package cn.xiaoge.day10.demo06;
      
      public abstract class Animal {
      
          public abstract void eat();
      
      }
      
    • Cat类

      package cn.xiaoge.day10.demo06;
      
      public class Cat extends Animal {
      
          @Override
          public void eat() {
              System.out.println("猫吃鱼");
          }
      
          // 子类特有方法
          public void catchMouse() {
              System.out.println("猫爪老鼠");
          }
      
      }
      
    • Dog类

      package cn.xiaoge.day10.demo06;
      
      public class Dog extends Animal {
      
          @Override
          public void eat() {
              System.out.println("狗吃SHIT");
          }
      
          public void watchHouse() {
              System.out.println("狗看家");
          }
      
      }
      
    • 执行路口

      package cn.xiaoge.day10.demo06;
      
      /*
      向上转型一定是安全的, 没有问题的, 正确的. 但是也有一个弊端:
      对象一旦向上转型为父类, 那么就无法调用子类原本特有的内容.
      
      解决方案: 用对象的向下转型[还原].
      
      
      1. 对象的向上转型, 其实就是多态写法:
      格式: 父类名称 对象名 = new 子类名称();      Animal animal = new Cat();
      含以: 右侧创建一个子类对象, 把它当做父类来看待使用.    创建了一只猫, 当做动物看待, 没问题.
      注意事项:
          向上转型一定是安全的. 从小范围转向大范围, 从小范围的猫, 向上转换成为更大范围的动物.
      类似于:
      double num = 100; // 正确, int ---> double, 自动类型转换.
      
      2. 对象向下转型, 其实是一个[还原]的动作.
      格式: 子类名称 对象名 = (子类名称) 父类对象;
      含以: 将父类对象, [还原] 成为本来的子类对象.
      Animal animal = new Cat(); // 本来是猫, 向上转型成为动物
      Cat cat = (Cat) animal; // 本来是猫, 已经被当做动物了, 还原回来成为本来的猫.
      注意事项:
          1. 必须保证对象本来创建的时候, 就是猫, 才能向下转型成为猫.
          2. 如果对象创建的时候本来不是猫, 现在非要向下转型成为猫, 就会报错. ClasscastException
      类似于: int num = (int) 10.0; // 可以    int num = (int) 10.5 // 不可以,精度损失
      
       */
      
      public class Demo01Main {
      
          public static void main(String[] args) {
              // 对象向上转型, 就是: 父类引用指向子类对象.
              Animal animal = new Cat(); // 本来创建的时候是一只猫
              animal.eat(); // 猫吃鱼
      
              // animal.catchMouse(); // 错误写法
      
              // 向下转型, 进行"还原"动作
              Cat cat = (Cat) animal;
              cat.catchMouse(); // 猫爪老鼠
      
              // 下面是错误的向下转型
              // 本来new的时候是一只猫, 现在非要当做狗
              // 错误写法! 编译不会报错, 但是会出现异常:
              // java.lang.ClasscastException, 类转换异常.
              // Dog dog = (Dog) animal;
      
          }
      
      }
      
      // 运行结果
      猫吃鱼
      猫爪老鼠
      
    • 执行路口

      package cn.xiaoge.day10.demo06;
      
      /*
      如何才能知道一个父类引用的对象, 本来是什么子类?
      格式:
      对象 instanceof 类型
      这将得到一个boolean值结果, 也就是判断前面的对象能不能当做后面类型的实例.
       */
      
      public class Demo02Instanceof {
      
          public static void main(String[] args) {
              Animal animal = new Dog(); // 本来是一只狗
              animal.eat(); // 狗吃SHIT
      
              giveMeAPet(animal);
          }
      
          public static void giveMeAPet(Animal animal) {
              // 如果希望调用子类特有的方法, 需要向下转型
              // 判断一下父类引用animal本来是不是Dog
              if (animal instanceof Dog) {
                  Dog dog = (Dog) animal;
                  dog.watchHouse();
              }
      
              // 判断一下animal本来是不是Cat
              if (animal instanceof Cat) {
                  Cat cat = (Cat) animal;
                  cat.catchMouse();
              }
          }
      
      }
      
      // 运行结果
      狗吃SHIT
      狗看家
      
  4. 案例

    • USB接口

      package cn.xiaoge.day10.demo07;
      
      public interface USB {
      
          public abstract void open();
      
          public abstract void close();
      
      }
      
    • Mouse类

      package cn.xiaoge.day10.demo07;
      
      // 鼠标就是一个USB鼠标
      public class Mouse implements USB {
      
          @Override
          public void open() {
              System.out.println("打开鼠标");
          }
      
          @Override
          public void close() {
              System.out.println("关闭鼠标");
          }
      
          public void click() {
              System.out.println("点击鼠标");
          }
      
      }
      
    • Keyboard类

      package cn.xiaoge.day10.demo07;
      
      // 键盘就是一个USB键盘
      public class Keyboard implements USB {
      
          @Override
          public void open() {
              System.out.println("打开键盘");
          }
      
          @Override
          public void close() {
              System.out.println("关闭键盘");
          }
      
          public void type() {
              System.out.println("键盘输入");
          }
      
      }
      
    • Computer类

      package cn.xiaoge.day10.demo07;
      
      
      public class Computer {
      
          public void powerOn(){
              System.out.println("打开电脑");
          }
      
          public void powerOff() {
              System.out.println("关闭电脑");
          }
      
          // 使用USB设备的方法, 使用接口作为方法的参数
          public void useDevice(USB usb) {
              usb.open(); // 打开设备
      
              // 判断一下接口引用usb本来是不是Mouse
              if (usb instanceof Mouse) {
                  Mouse mouse = (Mouse) usb; // 向下转型
                  mouse.click();
              }
      
              // 判断一下接口引用usb本来是不是Keyboard
              if (usb instanceof Keyboard) {
                  Keyboard keyBoard = (Keyboard) usb; // 向下转型
                  keyBoard.type();
              }
      
              usb.close(); // 关闭设备
          }
      
      }
      
    • 执行路口

      package cn.xiaoge.day10.demo07;
      
      public class DemoMain {
      
          public static void main(String[] args) {
              // 首先创建一个笔记本电脑
              Computer computer = new Computer();
              // 打开电脑
              computer.powerOn();
      
              // ***多态写法***
              // 把鼠标对像向上转型, 供电脑使用
              USB usbMouse = new Mouse();
              // 参数USB类型, 我正好传递进去的就是USB鼠标
              computer.useDevice(usbMouse);
      
              // 把键盘对象向上转型, 供电脑使用
              USB usbKeyboard = new Keyboard();
              // 参数USB类型, 我正好传递进去的就是USB键盘
              computer.useDevice(usbKeyboard);
      
              System.out.println("==========================");
      
              // ***实例类写法***
              // 创建一个USB鼠标
              Mouse mouse = new Mouse();
              // 方法参数是USB类型, 传递进去的是实现类对象
              computer.useDevice(mouse); // 正确写法! 也发生了向上转型
      
              // 创建一个USB键盘
              Keyboard keyBoard = new Keyboard();
              // 方法参数是USB类型, 传递进去的是实现类对象
              computer.useDevice(keyBoard); // 正确写法! 也发生了向上转型
      
              // 关闭电脑
              computer.powerOff();
      
      
              System.out.println("==========================");
              // 解释为什么USB类型可以传递实现类对象
              // 这里用的基本类型自动转换做案例
              method(10.0); // 正确写法, double ---> double
              method(20); // 正确写法, int ---> double
          }
      
          public static void method(double num) {
              System.out.println(num);
          }
      
      }
      
      // 运行结果
      打开电脑
      打开鼠标
      点击鼠标
      关闭鼠标
      打开键盘
      键盘输入
      关闭键盘
      ==========================
      打开鼠标
      点击鼠标
      关闭鼠标
      打开键盘
      键盘输入
      关闭键盘
      关闭电脑
      ==========================
      10.0
      20.0
      
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!