JAVA之旅(八)——多态的体现,前提,好处,应用,转型,instanceof,多态中成员变量的特点,多态的案例

释放双眼,带上耳机,听听看~!

JAVA之旅(八)——多态的体现,前提,好处,应用,转型,instanceof,多态中成员变量的特点,多态的案例

JAVA之旅(八)——多态的体现,前提,好处,应用,转型,instanceof,多态中成员变量的特点,多态的案例

一.多态

我们今天又要学习一个新的概念了,就是多态,它是面向对象的第三个特征,何谓多态?

  • 定义

某一类事物的多种存在方式

  • 比如

动物中的猫狗,人类中的男人,女人

我们可以把多态理解为事物存在的多种体现形态

当我们new一个猫类的时候,和new 一个动物,其实是一样的,多种形态变现

所以我们可以分这几部分分析

    1. 多态的体现
  1. 多态的前提

  2. 3.多态的好处

  3. 4.多态的应用

我们定义一个需求,描述动物,正常的逻辑应该是这样描述的


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
1//公共的   类   类名
2public class HelloJJAVA {
3    // 公共的 静态 无返回值 main方法 数组
4    public static void main(String[] str) {
5        /**
6         * 动物: 猫,狗
7         */
8        Cat c = new Cat();
9        c.eat();
10        dog d = new dog();
11        d.eat();
12    }
13}
14
15/**
16 * 动物
17 *
18 * @author LGL
19 *
20 */
21abstract class Animal {
22
23    // 吃什么不确定,抽象
24    abstract void eat();
25}
26
27/**
28 * 猫
29 *
30 * @author LGL
31 *
32 */
33class Cat extends Animal {
34
35    @Override
36    void eat() {
37        System.out.println("猫吃鱼");
38    }
39
40}
41
42/**
43 * 狗类
44 *
45 * @author LGL
46 *
47 */
48class dog extends Animal {
49
50    @Override
51    void eat() {
52        System.out.println("狗吃骨头");
53    }
54
55}
56
57

这个体系我们展现出来一个为题,我们为了使用猫吃东西和狗吃东西,得new两个对象,要是多来几只小动物,我不还得new死,所以我们要想一个解决办法,他们有一个共性,就是都是动物,我们可以这样转换


1
2
3
1Animal a = new Cat();
2a.eat();
3

因为也是动物类型,我们输出

这就是多态在程序中的表现

  • 父类的引用指向了自己的子类对象,这就是多态的代码体现形式,人 = new 男人,换句话说,父类的引用也可以接收子类的对象,所以我们可以这样定义一个方法


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1//公共的   类   类名
2public class HelloJJAVA {
3    // 公共的 静态 无返回值 main方法 数组
4    public static void main(String[] str) {
5        /**
6         * 动物: 猫,狗
7         */
8        AnimalEat(new Cat());
9        AnimalEat(new dog());
10    }
11
12    public static void AnimalEat(Animal a) {
13        a.eat();
14    }
15}
16

这样就方便了,这样也就体现了多态的好处:

  • 多态的出现大大的提升了程序的扩展性

但是有前提的

  • 必须类与类之间有关系,要么继承,要么实现
  • 通常,还有一个前提就是存在覆盖

不过,有利有弊,还是会存在弊端的

  • 提高了扩展性,但是只能使用父类的引用访问父类的成员,这是局限性,但是我们侧重扩展性

我们再返回前面说多态的转型,我们看这段代码


1
2
3
4
1//类型提升
2Animal a = new Cat();  
3a.eat();
4

我们也叫作向上转型,

如果想要调属性,该如何操作(向下转型)?

  • 强制将父类的引用转为子类类型


1
2
3
4
5
6
1        Animal a = new Cat();
2        a.eat();
3
4        Cat c = (Cat)a;
5        c.sleep();
6

也就是说,转型是强制将父类的引用,转为子类类型,向下转型。千万不要将父类对象转成子类对象,我们能转换的是父类引用指向子类对象的子类,多态自始至终都是子类对象在做着变化

那么你会了强转之后,你就说,我可以这样做


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1//公共的   类   类名
2public class HelloJJAVA {
3    // 公共的 静态 无返回值 main方法 数组
4    public static void main(String[] str) {
5        /**
6         * 动物: 猫,狗
7         */
8
9        AnimalEat(new Cat());
10        AnimalEat(new dog());
11
12    }
13
14    public static void AnimalEat(Animal a) {
15        a.eat();
16
17        Cat c = (Cat) a;
18        c.sleep();
19    }
20}
21

这样是不是可以?我们看结果

这里报错了,提示的是狗类型不行转换成猫类型,的确,不能随便乱转。我们价格判断,怎么判断呢?条件语句该怎么写呢?这里我们又有一个关键字了instanceof


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1//公共的   类   类名
2public class HelloJJAVA {
3    // 公共的 静态 无返回值 main方法 数组
4    public static void main(String[] str) {
5        /**
6         * 动物: 猫,狗
7         */
8
9        AnimalEat(new Cat());
10        AnimalEat(new dog());
11
12    }
13
14    public static void AnimalEat(Animal a) {
15        a.eat();
16
17        //如果a的类型是Cat就执行
18        if(a instanceof Cat){
19            Cat c = (Cat) a;
20            c.sleep();
21        }
22
23    }
24}
25

这样我们加了判断之后,我们就可以知道

既然多态说了这么多,我们来看看多态的应用吧,还是以一个需求开始去分析


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
1//公共的   类   类名
2public class HelloJJAVA {
3    // 公共的 静态 无返回值 main方法 数组
4    public static void main(String[] str) {
5
6        /**
7         * 需求:幼儿园有两个班 大班: 学习,睡觉 小班: 学习,睡觉 可以将两类事物进行抽取
8         */
9        SmallClass s = new SmallClass();
10        s.study();
11        s.sleep();
12
13        BigClass b = new BigClass();
14        b.study();
15    }
16
17}
18
19/**
20 * 学生类
21 *
22 * @author LGL
23 *
24 */
25abstract class Student {
26    // 学习的内容不一样,抽象
27    public abstract void study();
28
29    // 睡觉
30    public void sleep() {
31        System.out.println("躺着睡");
32    }
33}
34
35/**
36 * 大班
37 *
38 * @author LGL
39 *
40 */
41class BigClass extends Student {
42
43    @Override
44    public void study() {
45        System.out.println("学习大班知识");
46    }
47
48}
49
50/**
51 * 小班
52 *
53 * @author LGL
54 *
55 */
56class SmallClass extends Student {
57
58    @Override
59    public void study() {
60        System.out.println("学习小班知识");
61    }
62
63    @Override
64    public void sleep() {
65        System.out.println("卧着睡");
66    }
67
68}
69

这个例子输出

你拿到一想,是不是根据上面的方法直接复用父类对象的引用?这里我们可以拿到一个单独的类去复用封装


1
2
3
4
5
6
7
8
9
10
11
12
13
1/**
2 * 封装工具类
3 *
4 * @author LGL
5 *
6 */
7class DoStudent {
8    public void dosome(Student s) {
9        s.study();
10        s.sleep();
11    }
12}
13

这样我们使用


1
2
3
4
1        DoStudent dos = new DoStudent();
2        dos.dosome(new BigClass());
3        dos.dosome(new SmallClass());
4

得到的结果

我们再来看下多态的代码特点,我们举个例子


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1//公共的   类   类名
2public class HelloJJAVA {
3    // 公共的 静态 无返回值 main方法 数组
4    public static void main(String[] str) {
5        zi z = new zi();
6        z.method1();
7        z.method2();
8        z.method3();
9    }
10}
11
12class Fu {
13    void method1() {
14        System.out.println("fu method1");
15    }
16
17    void method2() {
18        System.out.println("fu method2");
19    }
20}
21
22class zi extends Fu {
23    void method1() {
24        System.out.println("zi method1");
25    }
26
27    void method3() {
28        System.out.println("zi method3");
29    }
30
31}
32

你能告诉我打印的结果吗?

我们现在用多态的思想去做

你会知道,3是引用不了的,我现在把报错的的地方注释掉,然后你能告诉我运行的结果吗

我们可以总结出特点(在多态中成员函数的特点)

  • 在编译时期。参阅引用型变量所属的类是否有调用的方法,如果由,编译通过。如果没有编译失败
  • 在运行时期,参阅对象所属的类中是否有调用的方法
  • 简单总结就是成员函数在多态调用时,编译看左边,运行看右边

我们再在子类和父类中都定义一个int值分别是5和8

我们这么输出


1
2
3
4
5
6
1        Fu f = new zi();
2        System.out.println(f.num);
3
4        zi z = new zi();
5        System.out.println(z.num);
6

输出多少呢?

这里就总结出

  • 在多态中,成员变量的特点:无论编译和运行,都参考左边(引用型变量所属)
  • 在多态中,静态成员变量的特点:无论编译和运行,都参考左边

我们把学到的应用在案例上


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1//公共的   类   类名
2public class HelloJJAVA {
3    // 公共的 静态 无返回值 main方法 数组
4    public static void main(String[] str) {
5
6        /**
7         * 需求:电脑运行实例,电脑运行基于主板
8         */
9        MainBoard b = new MainBoard();
10        b.run();
11    }
12}
13
14/**
15 * 主板
16 *
17 * @author LGL
18 *
19 */
20class MainBoard {
21
22    public void run() {
23        System.out.println("主板运行了");
24    }
25
26}
27

我们程序这样写, 无疑看出来很多弊端,我想上网,看电影,他却没有这功能,我们要怎么去做,我们重新设计程序,再增加


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1/**
2 * 网卡
3 *
4 * @author LGL
5 *
6 */
7class NetCard {
8    public void open() {
9        System.out.println("打开网络");
10    }
11
12    public void close() {
13        System.out.println("关闭网络");
14    }
15}
16

但是这样,还是主板的耦合性是在是太强了,不适合扩展,所以,这个程序一定不是一个好的程序我,我们重新设计,用一个标准的接口


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
1import javax.print.attribute.standard.MediaName;
2
3//公共的   类   类名
4public class HelloJJAVA {
5    // 公共的 静态 无返回值 main方法 数组
6    public static void main(String[] str) {
7
8        /**
9         * 需求:电脑运行实例,电脑运行基于主板
10         */
11        MainBoard m = new MainBoard();
12        m.run();
13        // 没有设备,有设备的话之类传进去
14        m.userPCI(null);
15
16    }
17}
18
19/**
20 * 扩展接口
21 *
22 * @author LGL
23 *
24 */
25interface PCI {
26    public void open();
27
28    public void close();
29}
30
31/**
32 * 主板
33 *
34 * @author LGL
35 *
36 */
37class MainBoard {
38
39    public void run() {
40        System.out.println("主板运行了");
41    }
42
43    public void userPCI(PCI p) {
44        if (p != null) {
45            p.open();
46            p.close();
47        } else {
48            System.out.println("没有设备");
49        }
50
51    }
52
53}
54

我们现在不管增加听音乐还是上网的功能,只要实现PCI的接口,就可以实现,我们现在增加一个上网功能,该怎么做?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
1
2//公共的   类   类名
3public class HelloJJAVA {
4    // 公共的 静态 无返回值 main方法 数组
5    public static void main(String[] str) {
6
7        /**
8         * 需求:电脑运行实例,电脑运行基于主板
9         */
10        MainBoard m = new MainBoard();
11        m.run();
12        // 没有设备
13        m.userPCI(null);
14
15        // 有设备
16        m.userPCI(new NetCard());
17
18    }
19}
20
21/**
22 * 扩展接口
23 *
24 * @author LGL
25 *
26 */
27interface PCI {
28    public void open();
29
30    public void close();
31}
32
33/**
34 * 主板
35 *
36 * @author LGL
37 *
38 */
39class MainBoard {
40
41    public void run() {
42        System.out.println("主板运行了");
43    }
44
45    public void userPCI(PCI p) {
46        if (p != null) {
47            p.open();
48            p.close();
49        } else {
50            System.out.println("没有设备");
51        }
52
53    }
54
55}
56
57/**
58 * 网卡
59 *
60 * @author LGL
61 *
62 */
63class NetCard implements PCI {
64    public void open() {
65        System.out.println("打开网络");
66    }
67
68    public void close() {
69        System.out.println("关闭网络");
70    }
71}
72

这样我们运行

现在的主板是不是扩展性特别强,这就是多态的扩展性

原文地址http://www.bieryun.com/2720.html

给TA打赏
共{{data.count}}人
人已打赏
安全技术

详解Node.js API系列 Http模块(2) CNodejs爬虫实现

2021-12-21 16:36:11

安全技术

从零搭建自己的SpringBoot后台框架(二十三)

2022-1-12 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索