面向对象之多态

多态:同一个类型的多个实例,在执行同一个方法时,呈现出多种的行为特征
1
2
3
4
5
6
//“铠甲勇士”类
public class 铠甲勇士 {
public void skill(String name){
System.out.println(name + ":普通攻击");
}
}
1
2
3
4
5
6
7
8
9
//“刑天铠甲”类继承了“铠甲勇士”类
public class 刑天铠甲 extends 铠甲勇士{
private static String name = "刑天铠甲";
//重写“铠甲勇士”类skill方法
@Override
public void skill(String name){
System.out.println(name + ":火光剑法");
}
}
1
2
3
4
5
6
7
//“飞影铠甲”类继承了“铠甲勇士”类
public class 飞影铠甲 extends 铠甲勇士{
//新增features方法
public void features(){
System.out.println("飞影铠甲特征:蓝色");
}
}
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
//“铠甲功能”类
public class 铠甲功能 {
private static String name;
public static void main(String[] args){
铠甲功能.技能释放();
铠甲功能.铠甲特征();
}
//向上转型,子类对象直接赋值给父类对象
public static void 技能释放(){
// 动态绑定“刑天铠甲”类的skill方法,编译类型是“铠甲勇士”,实际类型是“刑天铠甲”
铠甲勇士 刑天技能 = new 刑天铠甲();
name = "刑天铠甲";
刑天技能.skill(name);
// 动态绑飞影铠甲类的skill方法,若无,则向父类查找,编译类型是”铠甲勇士“,实际类型是飞影铠甲
铠甲勇士 飞影技能 = new 飞影铠甲();
name = "飞影铠甲";
飞影技能.skill(name);
}
//向下转型,父类对象赋值给子类对象,需要强转类型
public static void 铠甲特征(){
铠甲勇士 飞影技能 = new 飞影铠甲();
// 于编译器而言,“飞影技能”是“铠甲勇士”类型(实际运行时是“飞影铠甲”类型),由于“铠甲勇士”类下并没有features方法,所以编译报错,实际可以运行
// 飞影技能.features();
// 强制类型转换,将“铠甲勇士”类型的“飞影技能”强转为“飞影铠甲”类型,“飞影铠甲”类有features()方法,故不会报错
飞影铠甲 铠甲类型强转 = (飞影铠甲)飞影技能;
铠甲类型强转.features();
}
}

运行“铠甲功能”类,输出:

1
2
3
4
5
刑天铠甲:火光剑法
飞影铠甲:普通攻击
飞影铠甲特征:蓝色
//小类赋值给大类称为向上转型,子类对象直接赋值给父类对象
//大类赋值给小类称为向下转型,父类对象赋值给子类对象,需要强转类型

ClassCastException错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void 铠甲特征(){
铠甲勇士 飞影技能 = new 飞影铠甲();
// 于编译器而言,“飞影技能”是“铠甲勇士”类型(实际运行时是“飞影铠甲”类型),由于“铠甲勇士”类下并没有features方法,所以编译报错,实际可以运行
飞影技能.features();
// 强制类型转换,将“铠甲勇士”类型的“飞影技能”强转为“飞影铠甲”类型,“飞影铠甲”类有features()方法,故不会报错
飞影铠甲 铠甲类型强转 = (飞影铠甲)飞影技能;
铠甲类型强转.features();

// ClassCastException
// 将刑天铠甲类型变量(实际类型)转换为飞影铠甲类型变量时,将会发生错误
// 报错:刑天铠甲 cannot be cast to 飞影铠甲
铠甲勇士 刑天技能 = new 刑天铠甲();
飞影铠甲 铠甲类型强转2 = (飞影铠甲)刑天技能;
}
// 结论:强转运算运算符只能给具有继承关系的编译类型做强转,否则编译错误

第二种ClassCastException错误

1
2
3
4
5
6
7
8
public static void test(){
// value1编译时类型为Object,实际类型为String
Object value1 = "123";
// Integer继承于Object,所以编译时不会报错
Integer value2 = (Integer)value1;
// 运行时报错java.lang.String cannot be cast to java.lang.Integer
}
// 结论:具有继承关系的编译类型强制转换时,如果被转变量的实际类型不是要转的目标类型,则运行错误

instanceof运算符:避免ClassCastException异常
1
2
3
4
5
6
7
8
9
10
//运用该运算符,可以将test()方法改写为如下
public static void test(){
Object value1 = "123";
if (value1 instanceof Integer){
Integer value2 = (Integer)value1;
}
else{
System.out.println("String不能强转为Integer类型");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//那么铠甲特征()方法可修改为如下
public static void 铠甲特征(){
铠甲勇士 飞影技能 = new 飞影铠甲();
if (飞影技能 instanceof 飞影铠甲){
飞影铠甲 铠甲类型强转 = (飞影铠甲)飞影技能;
铠甲类型强转.features();
}
else {
System.out.println("飞影技能不能强转为飞影铠甲类型");
}

铠甲勇士 刑天技能 = new 刑天铠甲();
if (刑天技能 instanceof 飞影铠甲){
飞影铠甲 铠甲类型强转2 = (飞影铠甲)刑天技能;
}
else {
System.out.println("刑天技能不能强转为飞影铠甲类型");
}
}
//instanceof运算符可以确保被强制转换类型的变量确实可以强制转换,从而避免ClassCastException