# 多态
# 多态用法
// Animal.java
public class Animal {
public void move() {
System.out.println("Animal move");
}
}
// Cat.java
public class Cat extends Animal {
// 方法覆盖
public void move() {
System.out.println("走猫步~");
}
public void catchMouse() {
System.out.println("捉老鼠~");
}
}
// Bird.java
public class Bird extends Animal{
public void move() {
System.out.println("鸟在飞翔~");
}
public void sing() {
System.out.println("在唱歌~");
}
}
// Test01.java
public class Test01 {
public static void main(String[] args) {
// 创建 Animal 对象
Animal a = new Animal();
a.move(); // Animal move
// 创建 Cat 对象
Cat c = new Cat();
c.move(); // 走猫步~
// 创建 Bird 对象
Bird b = new Bird();
b.move(); // 鸟在飞翔~
// -----------------
// 多态
// 向上转型
Animal a1 = new Cat();
a1.move(); // 走猫步~
Animal a2 = new Bird();
a2.move(); // 鸟在飞翔~
// --------------------------
Animal a3 = new Cat();
/**
* 下面调用 catchMouse() 编译报错
* 错误: 找不到符号
* a3.catchMouse();
* ^
* 符号: 方法 catchMouse()
* 位置: 类型为Animal的变量 a3
* 原因:在编译的时候,编译器只知道a3变量的数据类型是Animal,也就是说它只会去Animal.class字节码中查找catchMouse()方法,结果没找到,
* 自然“静态绑定”就失败了,编译没有通过。就像以上描述的错误信息一样:在类型为Animal的变量a中找不到方法catchMouse()。
*/
// a3.catchMouse();
// ----------------------------
/**
* 向下转型,为了调用子类对象特有的方法
* 向下转型也就是强制类型转换 将Animal类型转换Cat类型
*/
Animal a4 = new Cat();
Cat c1 = (Cat) a4;
c1.catchMouse(); // 捉老鼠~
/**
* 向下转型 编译不报错,运行报错
* Exception in thread "main" java.lang.ClassCastException: class Bird cannot be cast to class Cat (Bird and Cat are in unnamed module of loader 'app')
* at Test01.main(Test01.java:45)
* 编译不报错:
* 因为编译器只知道a5变量是Animal类型,Animal类和Cat类之间存在继承关系,所以可以进行向下转型(前面提到过,只要两种类型之间存在继承关系,
* 就可以进行向上或向下转型),语法上没有错误,所以编译通过了
* 运行报错:
* 报 ClassCastException 错误,翻译为类型转换异常,这种异常通常出现在向下转型的操作过程当中,当类型不兼容的情况下进行转型出现的异常,
* 之所以出现此异常是因为在程序运行阶段a5 引用指向的对象是一只小鸟,然后我们要将一只小鸟转换成一只猫,这显然是不合理的,因为小鸟和猫之间是没有继承关系的。
*/
Animal a5 = new Bird();
// Cat a6 = (Cat) a5; // 编译不报错,运行报错
// 避免引发上面问题,通过使用 instanceof 运算符
System.out.println(a5 instanceof Cat); // false
System.out.println(a5 instanceof Bird); // true
System.out.println(a5 instanceof Animal); // true
// 先判断
if (a5 instanceof Cat) { // false
Cat c2 = (Cat) a5;
c2.catchMouse();
}else if(a5 instanceof Bird){ // true
Bird b2 = (Bird)a5;
b2.sing(); // 在唱歌~
}
}
}
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# instanceof 运算符
instanceof 运算符是用来测试一个对象是否为一个类的实例,运算结果是布尔类型,true或者false,假设(c instanceof Cat)结果是true则表示在运行阶段c引用指向的对象是Cat类型, 如果结果是false则表示在运行阶段c引用指向的对象不是Cat类型。在进行任何向下转型的操作之前,要使用instanceof进行判断,这是一个很好的编程习惯
语法格式:
对象 instanceof 类型
// 参考上面完整代码
Animal a5 = new Bird();
// 先判断
if (a5 instanceof Cat) {
Cat c2 = (Cat) a5;
c2.catchMouse();
}else if(a5 instanceof Bird){
Bird b2 = (Bird)a5;
b2.sing(); // 在唱歌~
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
多态存在的三个必要条件:
- 继承
- 方法覆盖
- 父类型引用指向子类型对象
多态显然是离不开方法覆盖机制的,多态就是因为编译阶段绑定父类当中的方法,程序运行阶段自动调用子类对象上的方法,如果子类对象上的方法没有进行重写, 这个时候创建子类对象就没有意义了,自然多态也就没有意义了,只有子类将方法重写之后调用到子类对象上的方法产生不同效果时,多态就形成了。实际上方法覆盖机制 和多态机制是捆绑的,谁也离不开谁,多态离不开方法覆盖,方法覆盖离开了多态也就没有意义了。