2020-05-17--Java--day10【多态】

多态概述

多态的格式和使用

代码当中体现多态性,其实就是一句话:父类引用指向子类对象。

格式:

  • 父类名称 对象名 = new 子类名称();
  • 接口名称 对象名 = new 实现类名称();

FU类:

public class Fu {

    public void method() {
        System.out.println("父类方法");
    }

    public void methodFu() {
        System.out.println("父类特有方法");
    }
}

ZI类:

public class Zi extends Fu {

    @Override
    public void method() {
        System.out.println("子类方法");
    }
}

main方法:

public class Demo01Multi {

    public static void main(String[] args) {
        // 使用多态的写法
        // 左侧父类的引用,指向了右侧子类的对象
        Fu obj = new Zi();

        obj.method();
        obj.methodFu();
    }
}

运行:


多态中成员变量和成员方法的使用特点

访问成员变量的两种方式:

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

在多态的代码当中,成员方法的访问规则是:
看new的是谁,就优先用谁,没有则向上找。
口诀:编译看左边,运行看右边。
对比一下:
成员变量:编译看左边,运行还看左边。
成员方法:编译看左边,运行看右边。
意思是:在调用成员变量或者成员方法时,要看等号左边的类中是否有该变量或者该方法。

FU类:

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

}

ZI类:

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

main方法:

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();
        
        //成员方法的使用
        obj.method(); // 父子都有,优先用子
        obj.methodFu(); // 子类没有,父类有,向上找到父类

        // 编译看左边,左边是Fu,Fu当中没有methodZi方法,所以编译报错。
//        obj.methodZi(); // 错误写法!
    }

}

总结:

  • 直接调用成员变量时,等号左边是谁,就用谁的成员变量,没有就向上找。
  • 调用成员方法时,new的是谁的对象,就优先用谁的方法,没有就想上找,但是当在子类中找到该成员方法时,父类中必须要有该方法。
Fu obj = new Zi();
含义:受父类限制的子类对象,优先执行子类中复写的父类方法,但是不能执行父类中没有的方法。

使用多态的好处

对象的上下转型

向上转型:

向上转型就是类似于多态写法,加入猫继承于动物类,那么将猫看作动物就没毛病,

创建格式::父类 obj = new 子类();

举例:

Animal类:

public abstract class Animal {

    public abstract void eat();

}

Cat 类:

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

main方法:

public class Demo01Main {

    public static void main(String[] args) {
        // 对象的向上转型,就是:父类引用指向之类对象。
        Animal animal = new Cat(); // 本来创建的时候是一只猫
        animal.eat(); // 猫吃鱼

//        animal.catchMouse(); // 错误写法!

但是这是再调用子类中特有的方法时,就会报错,因为这时对象已经向上转型,不能调用子类中父类没有的方法。

向下转型

对象的向下转型其实是一个还原动作,类似于强制类型转换。当猫类向上转型到动物类后,再向下转型为猫时,没问题。但是如果将这个之前是猫的动物类向下转型为狗时,就不对了。

创建格式:子类名称 对象名 = (子类名称) 原本父类对象名;

含义:将父类对象还原为子类对象。

注意事项:在向下转型之前,必须保证该对象在创建时就是该子类的对象(猫),这样才能再次向下转型为猫。
如果不是一个子类的话,就会报出ClassCastException的错误。

举例:

Animal类:

public abstract class Animal {

    public abstract void eat();
}

Cat类:

public class Cat extends Animal {

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    // 子类特有方法
    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}

Dog类:

public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃SHIT");
    }

    public void watchHouse() {
        System.out.println("狗看家");
    }
}

main类:

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;
    }

}

分析:

  1. 在向上转型后,父类对象animal不能调用子类Cat的特有方法,那么对他进行向下转型,然后就可以调用了。
  2. 将父类对象animal转为子类Dog时,编译不会报错,但是运行异常java.lang.ClassCastException,类转换异常
  3. 说明只能向下转型为之前创建对象时的子类。

类型判断----instanceof关键字

在上一步中,我们是怎么知道该父类对象animal之前的引用是猫还是狗。

所以要进行类型的判断,使用instanceof关键字。
instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为:
对象名称 instanceof 类名称

实例:

/*
如何才能知道一个父类引用的对象,本来是什么子类?
格式:
对象 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();
        }
        // 调用给宠物的方法,传进去Dog类对象
        giveMeAPet(animal);
    }

    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();
        }
    }
}

分析:

  1. 首先创建Dog类对象,向上转型为Animal类,在使用时,由于不知道该对象之前是哪个类的对象,所以要进行判断该对象是什么类型的类对象,使用instanceof关键字,返回bool值,进而进行向下转型,就可以调用该子类中的特有方法了。

笔记本接口案例

  • 笔记本电脑(laptop)通常具备使用USB设备的功能。在生产时,笔记本都预留了可以插入USB设备的USB接口,
    但具体是什么USB设备,笔记本厂商并不关心,只要符合USB规格的设备都可以。
  • 定义USB接口,具备最基本的开启功能和关闭功能。鼠标和键盘要想能在电脑上使用,那么鼠标和键盘也必须遵守USB规范,实现USB接口,否则鼠标和键盘的生产出来也无法使用。

分析

进行描述笔记本类,实现笔记本使用USB鼠标、USB键盘

  • USB接口,包含开启功能、关闭功能
  • 笔记本类,包含运行功能、关机功能、使用USB设备功能
  • 鼠标类,要实现USB接口,并具备点击的方法
  • 键盘类,要实现USB接口,具备敲击的方法

图例:

代码:
1.定义USB接口:
该接口有两个抽象类--打开设备和关闭设备

public interface USB {

    public abstract void open(); // 打开设备

    public abstract void close(); // 关闭设备

}

2.定义鼠标类和(键盘类)
这两个类继承USB接口,实现接口中的抽象方法,并有独有的动作方法--click()和type()

// 鼠标就是一个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("鼠标点击");
    }
}
// 键盘就是一个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("键盘输入");
    }
}

3.定义电脑类
电脑类实现独有方法--开机和关机。
定义使用USB设备的方法,该方法的参数类型为USB类型,在方法中
首先打开设备(执行公有方法打开设备),判断设备类型,执行设备特有方法,关闭设备(执行共有方法)

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(); // 关闭设备
    }

}

Main:

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);
    }

}

Main函数分析:

  1. 首先创建一个笔记本类,执行笔记本的开机方法(powerOn)。
  2. 接入鼠标时,使用多态写法将鼠标类向上转型为USB接口类创建对象,将该对象传入电脑类的USB使用方法中(useDevice),这是常规写法,符合要求,进而在该方法中执行鼠标类中实现USB接口类的打开设备和关闭设备的两个方法,并判断类型为鼠标类,执行独有方法--点击(click)。
  3. 接入键盘,不在显式的将键盘类向上转为USB接口类,采用正常写法创建键盘类对象,进而调用电脑类的使用USB的方法,将键盘对象传进去,执行该方法。(与鼠标执行一致)
  • 第三部也是正确的,原因就是发生了类似于自动类型转换的情况,例如:定义一个接受double类型参数的方法,当传入int类型时,也是可以的,发生自动类型转换,将int转为double类型。

4.关闭电脑--执行powerOff方法。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352