博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第四章 –– 多态的概念
阅读量:4553 次
发布时间:2019-06-08

本文共 13923 字,大约阅读时间需要 46 分钟。

第四章 –– 多态的概念

 

1. 被private修饰的方法变失去了多态的能力,它不存在重写,即使子类有有同名方法也只能算新方法

2. 只有方法存在多态性,如果父类个子类存在相同字段,此时产生多态,使用父类引用直接调用字段时发现这个字段是父类的值,这里值得探讨,如果调用的是读取字段的方法呢?还是显示父类的值么???
结果子类的字段值。。。
总结:多态探讨的是方法调用的多态,而不是字段的多态,从多态的本质可以看出,多态无非是多了一个vptr指针指向一个虚函数表,表内存的都是函数指针,并未有字段,调用虚函数表中的函数才有区分是调用的父类还是子类

探讨构造器和成员变量直接初始化的顺序?//TODO

 
准则,尽量在构造方法中调用简单的方法
,比如final或者private(默认这种方法也为final标识的方法),这样在能避免多态构造方法中的问题。
 
在构造方法中存在多态问题,还是要跟着多态的本质走。但是这个本质和c++的多态原则不同:
c++ 的多态实现方法是:
    前提: 父类指针或者引用指向子类对象, 
        在父类指针出现时, vptr指针也带着出现了, 这个时候因为继承的关系(vptr指针指向谁是由调用构造函数并在构造函数执行前完成了对vptr指针的初始化), 在执行父类的构造函数时, vptr指针将被指向父类的虚函数表(虚函数表的出现前提是存在virtual标识函数时就会产生虚函数表和虚函数指针), 当在执行子类的构造函数时, 虚函数指针才会被指向正确的虚函数表, 这就是c++实现多态虚函数指针初始化的过程
java的多态实现方法是: ???  估计是基本的和上面一样, 只不过vptr指针初始化被优化了, 提前指向了子类的虚函数表 //TODO
c++代码实现
或者引用
 
 
39
 
 
 
1
#include 
2
using namespace std;
3
 
4
class Parent
5
{
6
protected:
7
   virtual void draw() {
8
       cout << "Parent draw" << endl;
9
   }
10
public:
11
   Parent() {
12
       cout << "Parent 构造方法调用前 " << endl;
13
       draw();
14
       cout << "Parent 构造方法调用后 " << endl;
15
   }
16
};
17
 
18
 
19
class Child : public Parent
20
{
21
public:
22
   Child() {
23
       cout << "Child 构造方法调用前 " << endl;
24
       cout << "Child 构造方法调用后 " << endl;
25
   }
26
protected:
27
   virtual void draw() {
28
       cout << "Child draw: " << a << endl;
29
   }
30
 
31
private:
32
   int a{ 10 };
33
};
34
 
35
 
36
int main(void) {
 
 
37
   Parent * p = new Child(); // 父类指针(或者引用)指向子类对象, 多态产生
38
   return 0;
39
}
 
 
 

java代码实现

 
 
 
43
 
 
 
 
 
1
package com.zhazha;
2
 
3
/**
4
* @author lenovo
5
* @version 1.0.0
6
* @date 2018/8/23 9:06
7
* @msg
8
**/
9
 
10
 
11
class Parent {
12
   public Parent() {
13
       System.out.println(" Parent 构造方法开始运行前....");
14
       draw();
15
       System.out.println(" Parent 构造方法开始运行前....");
16
   }
17
 
18
   public void draw() {
19
       System.out.println(" Parent draw ... ");
20
   }
21
}
22
 
23
class Child extends Parent {
24
   private int a = 10;
25
 
26
   public Child() {
27
       System.out.println(" Child 构造方法开始运行前....");
28
       System.out.println(" Child 构造方法开始运行后....");
29
   }
30
 
31
   public void draw() {
32
       System.out.println(" Child draw ... a == " + a);
33
   }
34
}
35
 
36
public class Demo {
37
 
38
   public static void main(String[] args) {
39
       Parent a = new Child();
40
   }
41
 
42
}
43
 
 
 
 

多态的概念

 
 
 
1
1
 
 
 
 
 
1
一个对象的一个或多个方法在同一个类族中穿梭时所表现的不同功能, 叫多态
 
 

多态成立的三要素

 
 
 
3
3
 
 
 
 
 
1
(1) 继承
2
(2) 函数重写
3
(3) 赋值兼容性原则
 
 

 

 

多态中的成员访问特点:

 
 
 
50
50
 
 
 
 
 
1
package com.bangiao.多态的成员范文特点01;
2
 
3
/*
4
* 多态中的成员访问特点:
5
*      (1) 成员变量
6
*          编译看左边, 运行看左边
7
*      (2) 构造方法
8
*          创建子类对象的时候, 访问父类的构造方法, 对父类的数据进行初始化
9
*      (3) 成员方法
10
*          编译看左边, 运行看右边
11
*      (4) 静态方法
12
*          编译看左边, 运行看左边
13
*      (静态和类相关, 算不上重写, 所以, 访问还是左边的)
14
*  由于成员方法存在方法重写, 所以它运行看右边
15
* */
16
 
17
class Fu
18
{
19
   public int num = 100;
20
   public void show()
21
   {
22
       System.out.println("show Fu");
23
   }
24
}
25
 
26
class Zi extends Fu
27
{
28
   public int num = 100;
29
   public void show()
30
   {
31
       System.out.println("show Zi");
32
   }
33
   public void method()
34
   {
35
       System.out.println("method zi");
36
   }
37
}
38
 
39
public class _Main
40
{
41
   public static void main(String[] args)
42
   {
43
       Fu f = new Zi();
44
       System.out.println(f.num);
45
//      System.out.println(f.num2);
46
       
47
       f.show();
48
//      f.method();
49
   }
50
}
 
 

 

 

--------------------------------------------------------------------------------

多态的好处

A: 提高了代码的维护性(由继承保证)

B: 提高了代码的扩展性(由多态保证)

多态的弊端

(1) 不能使用子类的特有功能

如果要使用的话直接强制转换成子类的引用变量

 

抽象类的特点:

 
 
 
10
10
 
 
 
 
 
1
A:抽象类和抽象方法必须用abstract关键字修饰
2
B:抽象类中不一定有抽象方法, 但是有抽象方法的类必须要定义为抽象类
3
C:抽象类不能实例化
4
   因为它不是具体的
5
抽象类有构造函数, 但是不能实例化, 那它有什么用?
6
   答: 用于子类访问父类数据的初始化
7
D:抽象类的之类
8
   a:如果不想重写抽象方法, 该子类是一个抽象类
9
   b:重写所有抽象方法, 这个时候子类是一个具体的类
10
抽象类想要实例化的话, 必须使用具体的子类来实现, 是多态的方式
 
 

抽象类的成员特点:

 
 
 
4
4
 
 
 
 
 
1
成员变量:既可以是变量, 也可以是常量
2
构造方法:有
3
   用于子类访问父类数据的初始化
4
成员方法:既可以是抽象的, 也可是非抽象的方法
 
 

 

 

抽象类的成员方法特性:

A:抽象方法   强制要求子类做的事情

B:非抽象方法   子类继承的事情提高代码复用性

 

抽象类中的小问题

一个类如果没有抽象方法可不可以定义为抽象类如果可以有什么意义?

A:可以

B:不让创建对象

 

abstract 不能和哪些关键字共存

 
 
 
3
3
 
 
 
 
 
1
private 冲突
2
final  冲突
3
static 无意义
 
 

 

接口名+Impl 

 

/*

 * 接口的成员特点:

 
 
 
14
14
 
 
 
 
 
1
* 成员变量: 只能是常量, 并且是静态的
2
* 默认修饰符: public static final
3
*     建议自己手动写出
4
* 构造方法: 接口没有构造方法
5
*     但是每个类在定义的时候默认都继承了 Object
6
*     public Zi extends Object implements Inter
7
*     这样的话即使接口没有构造函数的话, 也能通过Object
8
*     的构造方法进行初始化, 这个和抽象方法不用, 抽象方法
9
*     存在默认构造函数, 但是作用是相同的, 都是为了初始化字段
10
* 成员方法: 只能是抽象方法
11
*     默认修饰符是 public abstract
12
*     建议自己给出
13
*
14
* */
 
 

 

 

类与类类与接口接口与接口的关系

 
 
 
8
8
 
 
 
 
 
1
类与类:
2
   继承关系, 只能单继承, 可以多层继承
3
类与接口:
4
   实现关系, 可以单实现, 也可以多实现
5
   可以实现在继承一个类的同时实现多个接口
6
接口与接口
7
   接口与接口之间的关系是继承关系
8
   可以单继承也可以多继承
 
 

 

--------------------------------------------------------------------------------

 
 
 
55
55
 
 
 
 
 
1
package 类与类类与接口接口与接口的关系;
2
 
3
/*
4
   类与类:
5
       继承关系, 只能单继承, 可以多层继承
6
   类与接口:
7
       实现关系, 可以单实现, 也可以多实现
8
       可以实现在继承一个类的同时实现多个接口
9
   接口与接口
10
       接口与接口之间的关系是继承关系
11
       可以单继承也可以多继承
12
*/
13
interface Father
14
{
15
   public abstract void show();
16
}
17
 
18
interface Mother
19
{
20
   public abstract void show2();
21
}
22
 
23
interface Sisther extends Father, Mother
24
{
25
   
26
}
27
 
28
class Son extends Object implements Father, Mother
29
{
30
 
31
   @Override
32
   public void show2()
33
   {
34
       // TODO Auto-generated method stub
35
       System.out.println("show Mother Son");
36
   }
37
 
38
   @Override
39
   public void show()
40
   {
41
       // TODO Auto-generated method stub
42
       System.out.println("show Father Son");
43
   }
44
   
45
}
46
 
47
public class _main
48
{
49
   public static void main(String[] args)
50
   {
51
       Son s = new Son();
52
       s.show();
53
       s.show2();
54
   }
55
}
 
 

 

 

--------------------------------------------------------------------------------

 

抽象类和接口的区别

A:成员区别

 
 
 
8
8
 
 
 
 
 
1
抽象类:
2
   成员变量: 可以变量可以常量
3
   构造方法: 有
4
   成员方法: 可以抽象, 可以非抽象
5
接口:
6
   成员变量: 只可以常量
7
   成员方法: 只可以抽象
8
   构造方法: 无
 
 

B:关系区别

 
 
 
6
6
 
 
 
 
 
1
类与类
2
   继承, 单继承
3
类与接口
4
   实现, 单实现, 多实现
5
接口与接口
6
   继承, 单继承, 多继承
 
 

C:设计理念的区别

 
 
 
2
2
 
 
 
 
 
1
抽象类: 被继承的体现是共性关系
2
接口: 被实现体现的是拓展功能
 
 

 

何时使用接口何时使用抽象类

猫狗案例加入跳高功能代码实现

 
 
 
2
2
 
 
 
 
 
1
分析:
2
   从具体到抽象
 
 

 

:

姓名年龄

吃饭睡觉

:

姓名年龄

吃饭睡觉

 
 
 
1
1
 
 
 
 
 
1
由于有共性功能, 所以我们抽取出一个父类;
 
 

动物:

姓名年龄

吃饭(); // 吃饭吃的不同

睡觉(){}// 睡觉是一样的

继承自动物

继承自动物

 

 
 
 
1
1
 
 
 
 
 
1
跳高的额外功能是一个新的拓展功能, 所以我们定义一个接口
 
 

接口:

跳高

部分猫实现跳高

部分狗实现跳高

 
 
 
2
2
 
 
 
 
 
1
实现:
2
   从抽象到具体
 
 

 

--------------------------------------------------------------------------------

 
 
 
132
132
 
 
 
 
 
1
package 何时使用抽象何时接口;
2
 
3
// 定义接口
4
interface Jumpping {
5
public abstract void jump();
6
}
7
 
8
// 定义抽象类
9
abstract class Animal {
10
private String name;
11
private int age;
12
 
13
public Animal(String name, int age) {
14
super();
15
this.setName(name);
16
this.setAge(age);
17
}
18
 
19
public Animal() {
20
super();
21
}
22
 
23
public String getName() {
24
return name;
25
}
26
 
27
public void setName(String name) {
28
this.name = name;
29
}
30
 
31
public int getAge() {
32
return age;
33
}
34
 
35
public void setAge(int age) {
36
this.age = age;
37
}
38
 
39
// 吃饭
40
public abstract void eat();
41
 
42
// 睡觉
43
public void sleep() {
44
System.out.println("睡觉觉了");
45
}
46
}
47
 
48
// 具体猫类
49
class Cat extends Animal {
50
public Cat() {
51
super();
52
}
53
 
54
public Cat(String name, int age) {
55
super(name, age);
56
}
57
 
58
@Override
59
public void eat() {
60
System.out.println("猫吃鱼");
61
}
62
}
63
 
64
// 具体狗类
65
class Dog extends Animal {
66
public Dog() {
67
super();
68
}
69
 
70
public Dog(String name, int age) {
71
super(name, age);
72
}
73
 
74
@Override
75
public void eat() {
76
System.out.println("狗吃肉");
77
}
78
}
79
 
80
class JumpCat extends Cat implements Jumpping {
81
public JumpCat() {
82
super();
83
}
84
 
85
public JumpCat(String name, int age) {
86
super(name, age);
87
}
88
 
89
@Override
90
public void jump() {
91
System.out.println("跳高猫");
92
}
93
}
94
 
95
class JumpDog extends Dog implements Jumpping {
96
public JumpDog() {
97
super();
98
}
99
 
100
public JumpDog(String name, int age) {
101
super(name, age);
102
}
103
 
104
@Override
105
public void jump() {
106
System.out.println("跳高狗");
107
}
108
}
109
 
110
public class 猫狗案例加入调高功能 {
111
public static void main(String[] args) {
112
JumpCat jc = new JumpCat();
113
jc.setName("哆啦A梦");
114
jc.setAge(3);
115
System.out.println(jc.getName() + "---" + jc.getAge());
116
jc.eat();
117
jc.sleep();
118
jc.jump();
119
System.out.println("-----------------------------------");
120
JumpCat jc2 = new JumpCat("加菲猫", 2);
121
System.out.println(jc2.getName() + "---" + jc2.getAge());
122
jc2.eat();
123
jc2.sleep();
124
jc2.jump();
125
System.out.println("-----------------------------------");
126
JumpDog jd = new JumpDog("小黄", 4);
127
System.out.println(jd.getName() + "---" + jd.getAge());
128
jd.eat();
129
jd.sleep();
130
jd.jump();
131
}
132
}
 
 

 

 
 
 
99
99
 
 
 
 
 
1
package 学生老师案例加入抽烟功能;
2
 
3
/*
4
* 深刻理解抽象类和接口类的作用
5
*  抽象类是用于共性功能, 比如所有子类都有吃饭, 但是吃的东西不同, 这个就
6
* 可以独立出来
7
* 接口类主要的功能便是功能的扩展, 扩展一个子类的某个功能
8
* */
9
interface ISmoking {
10
public abstract void smoke();
11
}
12
 
13
abstract class AbsPerson {
14
private String name;
15
private int age;
16
 
17
public AbsPerson(String name, int age) {
18
super();
19
this.setName(name);
20
this.setAge(age);
21
}
22
 
23
public AbsPerson() {
24
super();
25
// TODO Auto-generated constructor stub
26
}
27
 
28
public String getName() {
29
return name;
30
}
31
 
32
public void setName(String name) {
33
this.name = name;
34
}
35
 
36
public int getAge() {
37
return age;
38
}
39
 
40
public void setAge(int age) {
41
this.age = age;
42
}
43
 
44
abstract public void eat();
45
 
46
public void sleep() {
47
System.out.println("睡觉了");
48
}
49
}
50
 
51
class TeacherImpl extends AbsPerson {
52
@Override
53
public void eat() {
54
// TODO Auto-generated method stub
55
System.out.println("吃大白菜");
56
}
57
}
58
 
59
class StudentImpl extends AbsPerson {
60
@Override
61
public void eat() {
62
// TODO Auto-generated method stub
63
System.out.println("吃红烧肉");
64
}
65
}
66
 
67
class SmokeTeacher extends TeacherImpl implements ISmoking {
68
@Override
69
public void smoke() {
70
// TODO Auto-generated method stub
71
System.out.println("老师抽烟");
72
}
73
}
74
 
75
class SmokeStudent extends StudentImpl implements ISmoking {
76
@Override
77
public void smoke() {
78
// TODO Auto-generated method stub
79
System.out.println("学生抽烟");
80
}
81
}
82
 
83
public class _Main {
84
public static void main(String[] args) {
85
SmokeStudent ss = new SmokeStudent();
86
ss.setAge(20);
87
ss.setName("meimei");
88
ss.eat();
89
ss.sleep();
90
ss.smoke();
91
System.out.println("--------------------------------");
92
SmokeTeacher st = new SmokeTeacher();
93
st.setAge(30);
94
st.setName("laoshi");
95
st.eat();
96
st.sleep();
97
st.smoke();
98
}
99
}
 
 

 

 

--------------------------------------------------------------------------------

多态的分类:

 
 
 
3
3
 
 
 
 
 
1
A:具体类多态
2
B:抽象类多态
3
C:接口类多态
 
 

 

多态的转型

 
 
 
5
5
 
 
 
 
 
1
A:向上转型
2
   从子到父
3
B:向下转型
4
   从父到子
5
案例: 孔子装爹
 
 

 

何时使用抽象类何时使用接口?

回顾猫狗案例:

它们仅仅提供了一些基本功能例如猫钻火圈狗跳高等功能这些功能不是这些动物特有的而是通过后天的训练出来的这种额外的功能java中提供了接口表示

星级酒店案例

 
 
 
 
x
152
 
 
 
 
 
1
11星级酒店案例
2
* A: 根据“某五星级酒店,资金雄厚……都有自己的工作要做。”分析出,该题目中包含酒店,可以把它封装成类,多名员工)。
3
 
4
class 员工 {
5
    属性:姓名
6
属性:工号
7
方法:工作
8
}
9
class 厨师 extends 员工{}
10
class 服务员 extends 员工{}
11
class 经理 extends 员工 {
12
    属性:奖金
13
}
14
 
15
员工的类型有经理、厨师、服务员,它们有共同的属性(姓名、工号、),经理额外属性(奖金)。
16
 
17
根据“向酒店中,增加多名员工(其中包含1名经理,1名厨师、2名服务员)”。分析出,要创建一个酒店对象,并添加4名员工到酒店对象的员工集合中。
18
酒店员工集合添加新员工: 经理对象
19
酒店员工集合添加新员工: 厨师对象
20
酒店员工集合添加新员工: 服务员对象
21
酒店员工集合添加新员工: 服务员对象
22
 
23
根据“获取酒店幸运员工”。分析出,从酒店员工集合随机得到一名员工对象。
24
1. 从酒店员工集合长度范围内,随机产生一个随机数
25
2. 使用该随机数作为集合的索引,返回该索引处对应的员工对象
26
 
27
根据“酒店开设VIP服务,酒店的厨师与服务员可以提供VIP服务。(厨师做菜加量、服务员给顾客倒酒)”。分析出,这是要增加一个VIP的接口,接口中提供个VIP服务的方法。让厨师与服务员实现该接口。
28
interface VIP服务{
29
    抽象方法:服务
30
}
31
class 厨师 extends 员工 implements VIP服务{ 重写服务方法 }
32
class 服务员 extends 员工 implements VIP服务{ 重写服务方法 }
33
 
34
B:
35
VIP服务
36
public interface VIP {
37
    public abstract void server(); //服务
38
}
39
 
40
员工
41
/*
42
* 员工:
43
姓名 String
44
工号 String
45
 
46
*/
47
public abstract class YuanGong {
48
// 成员变量
49
private String xingMing;
50
private String gongHao;
51
// 构造方法
52
public YuanGong() {
53
super();
54
}
55
public YuanGong(String xingMing, String gongHao) {
56
super();
57
this.xingMing = xingMing;
58
this.gongHao = gongHao;
59
 
60
}
61
// 抽象方法
62
public abstract void work();
63
 
64
// getters与setters
65
public String getXingMing() {
66
return xingMing;
67
}
68
public void setXingMing(String xingMing) {
69
this.xingMing = xingMing;
70
}
71
public String getGongHao() {
72
return gongHao;
73
}
74
public void setGongHao(String gongHao) {
75
this.gongHao = gongHao;
76
}
77
 
78
}
79
 
80
服务员
81
/*
82
* 定义员工的子类 服务员类
83
*/
84
public class FuWuYuan extends YuanGong implements VIP {
85
public FuWuYuan() {
86
super();
87
}
88
 
89
public FuWuYuan(String xingMing, String gongHao) {
90
super(xingMing, gongHao);
91
}
92
@Override
93
public void work() {
94
System.out.println("亲,全身心为您服务,记得给好评哦");
95
}
96
@Override
97
public void server() {
98
System.out.println("给顾客倒酒");
99
}
100
}
101
 
102
经理
103
/*
104
* 经理在员工的基础上,添加了奖金成员
105
*/
106
public class JingLi extends YuanGong {
107
private double jiangJin;
108
 
109
public JingLi() {
110
super();
111
}
112
public JingLi(String xingMing, String gongHao, double jiangJin) {
113
super(xingMing, gongHao);
114
this.jiangJin = jiangJin;
115
}
116
 
117
public double getJiangJin() {
118
return jiangJin;
119
}
120
public void setJiangJin(double jiangJin) {
121
this.jiangJin = jiangJin;
122
}
123
 
124
@Override
125
public void work() {
126
System.out.println("哪个员工让顾客不满意,我扣谁钱");
127
};
128
}
129
 
130
厨师
131
/*
132
* 定义员工的子类 厨师类
133
*/
134
public class ChuShi extends YuanGong implements VIP{
135
public ChuShi() {
136
super();
137
}
138
public ChuShi(String xingMing, String gongHao) {
139
super(xingMing, gongHao);
140
}
141
 
142
@Override
143
public void work() {
144
System.out.println("我做饭,放心吃吧,包您满意");
145
}
146
@Override
147
public void server() {
148
System.out.println("做菜加量加料");
149
}
150
}
151
 
152
 
 
 

 

 

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

 
 
 
 

转载于:https://www.cnblogs.com/bangiao/p/9508238.html

你可能感兴趣的文章
Dynamics CRM 给视图配置安全角色
查看>>
Eclipse修改已存在的SVN地址
查看>>
C++ ACM基础
查看>>
(转)使用 python Matplotlib 库绘图
查看>>
进程/线程切换原则
查看>>
正则表达式语法
查看>>
20165301 2017-2018-2 《Java程序设计》第四周学习总结
查看>>
Vue的简单入门
查看>>
urllib 中的异常处理
查看>>
通过SQL Server的扩展事件来跟踪SQL语句在运行时,时间都消耗到哪儿了?
查看>>
SQL优化:重新编译存储过程和表
查看>>
PCB“有铅”工艺将何去何从?
查看>>
Solr环境搭建
查看>>
垂直居中的几种实现方法
查看>>
UILabel标签文字过长时的显示方式
查看>>
H5离线缓存机制-manifest
查看>>
比较:I/O成员函数getline() 与 get()(第二种用法)的用法异同
查看>>
201671010118 2016-2017-2《Java程序设计》 第十一周学习心得
查看>>
Get Sauce(状压DP)
查看>>
Office2007 升级到 office2010
查看>>