• Java Object-Oriented:day10 【 Inheritance】


    一、多态的概述

    1、定义

    多态 : 是指同一行为,具有多个不同表现形式。

    2、前提

    1 . 继承或者实现【二选一】
    2. 方法的重写【意义体现:不重写,无意义】
    3. 父类引用指向子类对象【格式体现】

    3、图解

    二、多态的格式与使用

    1、定义子类

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

    2、定义父类

    package day10.demo04;
    
    public class Fu {
    
        public void method() {
            System.out.println("父类方法");
        }
    
    }

    如果子类没有

    package day10.demo04;
    
    public class Fu {
    
        public void method() {
            System.out.println("父类方法");
        }
    
        public void methodFu() {
            System.out.println("父类特有方法");
        }
    
    }

    3、定义测试类

    package day10.demo04;
    
    /*
    代码当中体现多态性,其实就是一句话:父类引用指向子类对象。
    
    格式:
    父类名称 对象名 = new 子类名称();
    或者:
    接口名称 对象名 = new 实现类名称();
     */
    public class Demo01Multi {
    
        public static void main(String[] args) {
            // 使用多态的写法
            // 左侧父类的引用,指向了右侧子类的对象
            Fu obj = new Zi();
    
            obj.method();
        }
    } 

    如果子类没有

    package day10.demo04;
    
    /*
    代码当中体现多态性,其实就是一句话:父类引用指向子类对象。
    
    格式:
    父类名称 对象名 = new 子类名称();
    或者:
    接口名称 对象名 = new 实现类名称();
     */
    public class Demo01Multi {
    
        public static void main(String[] args) {
            // 使用多态的写法
            // 左侧父类的引用,指向了右侧子类的对象
            Fu obj = new Zi();
    
            obj.method();
            obj.methodFu();
        }
    }

    4、运行结果

    子类方法

    如果子类没有

    子类方法
    父类特有方法

    三、多态中成员变量的使用特点

    1. 直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找。

    1、定义子类

    package day10.demo05;
    
    public class Zi extends Fu {
    
        int num = 20;
    
    }

    2、定义父类

    package day10.demo05;
    
    public class Fu /*extends Object*/ {
        int num = 10;
    }

    3、定义测试类

    package day10.demo05;
    
    /*
    访问成员变量的两种方式:
    
    1. 直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找。
    2. 间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找。
     */
    public class Demo01MultiField {
    
        public static void main(String[] args) {
            // 使用多态的写法,父类引用指向子类对象
            Fu obj = new Zi();
            System.out.println(obj.num); // 父:10
        }
    
    }

    4、运行结果

    10

    2. 间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找。

    1、定义子类

    package day10.demo05;
    
    public class Zi extends Fu {
    
        int num = 20;
    
        int age = 16;
    
        @Override
        public void showNum() {
            System.out.println(num);
        }
    }

    2、定义父类

    package day10.demo05;
    
    public class Fu /*extends Object*/ {
    
        int num = 10;
    
        public void showNum() {
            System.out.println(num);
        }
    
    }

    3、定义测试类

    package 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); // 错误写法!
            System.out.println("=============");
    
            // 子类没有覆盖重写,就是父:10
            // 子类如果覆盖重写,就是子:20
            obj.showNum();
        }
    
    }

    4、运行结果

    10
    =============
    20

    3、多态中成员方法的使用特有方法

    1、定义父类

    package day10.demo05;
    
    public class Fu /*extends Object*/ {
    
        int num = 10;
    
        public void showNum() {
            System.out.println(num);
        }
    
        public void method() {
            System.out.println("父类方法");
        }
    
        public void methodFu() {
            System.out.println("父类特有方法");
        }
    
    }

    2、定义子类

    package 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("子类特有方法");
        }
    }

    3、定义测试类

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

    4、运行结果

    子类方法
    父类特有方法

    四、使用多态的好处

     好处:无论右边new的时候换成那个子类对象,等号左边调用都不会变化

    五、对象的向上、下转型

    为什么要转型?

    当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。编译都错误,更别说运行了。
    这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型

     1、向上转型

    1、定义父类

    package day10.demo06;
    
    public abstract class Animal {
    
        public abstract void eat();
    
    }

    2、定义子类

    package day10.demo06;
    
    public class Cat extends Animal {
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    }

    3、定义测试类

    package day10.demo06;
    
    /*
    向上转型一定是安全的,没有问题的,正确的。但是也有一个弊端:
    对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。
    
    解决方案:用对象的向下转型【还原】。
     */
    public class Demo01Main {
    
        public static void main(String[] args) {
            // 对象的向上转型,就是:父类引用指向之类对象。
            Animal animal = new Cat(); // 本来创建的时候是一只猫
            animal.eat(); // 猫吃鱼
    
    }

    4、运行结果

    猫吃鱼

    2、向下转型

    1、定义父类

    package day10.demo06;
    
    public abstract class Animal {
    
        public abstract void eat();
    
    }

    2、定义子类

    dog

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

    cat

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

    3、定义测试类

    package day10.demo06;
    
    import day10.demo06.Animal;
    import day10.demo06.Cat;
    import day10.demo06.Dog;
    
    /*
    向上转型一定是安全的,没有问题的,正确的。但是也有一个弊端:
    对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。
    
    解决方案:用对象的向下转型【还原】。
     */
    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;
        }
    
    }

    4、运行结果

    猫吃鱼
    猫抓老鼠
    Exception in thread "main" java.lang.ClassCastException: class day10.demo06.Cat cannot be cast to class day10.demo06.Dog (day10.demo06.Cat and day10.demo06.Dog are in unnamed module of loader 'app')
    	at day10.demo06.Demo01Main.main(Demo01Main.java:30)

    3、图解

    六、用instanceof关键字进行

    1、转型的异常

    猫吃鱼
    猫抓老鼠
    Exception in thread "main" java.lang.ClassCastException: class day10.demo06.Cat cannot be cast to class day10.demo06.Dog (day10.demo06.Cat and day10.demo06.Dog are in unnamed module of loader 'app')
    	at day10.demo06.Demo01Main.main(Demo01Main.java:30)
    

    这段代码可以通过编译,但是运行时,却报出了 ClassCastException ,类型转换异常!这是因为,明明创建了Cat类型对象,
    运行时,当然不能转换成Dog对象的。这两个类型并没有任何继承关系,不符合类型转换的定义。

    2、instanceof 关键字,解决转型异常

    1、测试类

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

    2、运行结果

    狗吃SHIT
    狗看家
    狗看家

    七、笔记本USB接口案例

    1、案例分析

    2、案例实现代码

    1、Computer

    package day10.demo06;
    
    public class Computer {
    
        public void powerOn() {
            System.out.println("笔记本电脑开机");
        }
    
        public void powerOff() {
            System.out.println("笔记本电脑关机");
        }
    
        // 使用USB设备的方法,使用接口作为方法的参数
        public void useDevice(USB usb) {
            usb.open(); // 打开设备
            if (usb instanceof Mouse) { // 一定要先判断
                Mouse mouse = (Mouse) usb; // 向下转型
                mouse.click();
            } else if (usb instanceof Keyboard) { // 先判断
                Keyboard keyboard = (Keyboard) usb; // 向下转型
                keyboard.type();
            }
            usb.close(); // 关闭设备
        }
    
    }

    2、DemoMain

    package day10.demo06;
    
    public class DemoMain {
    
        public static void main(String[] args) {
            // 首先创建一个笔记本电脑
            Computer computer = new Computer();
            computer.powerOn();
    
            // 准备一个鼠标,供电脑使用
    //        Mouse mouse = new Mouse();
            // 首先进行向上转型
            USB usbMouse = new Mouse(); // 多态写法
            // 参数是USB类型,我正好传递进去的就是USB鼠标
            computer.useDevice(usbMouse);
    
            // 创建一个USB键盘
            Keyboard keyboard = new Keyboard(); // 没有使用多态写法
            // 方法参数是USB类型,传递进去的是实现类对象
            computer.useDevice(keyboard); // 正确写法!也发生了向上转型
            // 使用子类对象,匿名对象,也可以
    //        computer.useDevice(new Keyboard()); // 也是正确写法
    
            computer.powerOff();
            System.out.println("==================");
    
            method(10.0); // 正确写法,double --> double
            method(20); // 正确写法,int --> double
            int a = 30;
            method(a); // 正确写法,int --> double
        }
    
        public static void method(double num) {
            System.out.println(num);
        }
    
    }

    3、Keyboard

    package day10.demo06;
    
    // 键盘就是一个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("键盘输入");
        }
    }

    4、Mouse

    package day10.demo06;
    
    // 鼠标就是一个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("鼠标点击");
        }
    }

    5、USB

    package day10.demo06;
    public interface USB {
    
        public abstract void open(); // 打开设备
    
        public abstract void close(); // 关闭设备
    
    }
  • 相关阅读:
    计算机-MQ:Kafka
    DB:时序数据库
    软件-数据仓库工具:hive
    劳动者须防不良企业9类用工陷阱
    PHP+jQuery 注册模块的改进之三:使用 Smarty3
    Java实现 洛谷 P1009 阶乘之和
    Java实现 洛谷 P1009 阶乘之和
    C语言深入理解通过指针引用多维数组(指针中使用起始地址 元素地址 元素值的区分)...
    C语言深入理解通过指针引用多维数组(指针中使用起始地址 元素地址 元素值的区分)...
    C语言深入理解通过指针引用多维数组(指针中使用起始地址 元素地址 元素值的区分)...
  • 原文地址:https://www.cnblogs.com/luoahong/p/12830581.html
Copyright © 2020-2023  润新知