多态
一、初识多态
使用多态的原因
- 宠物饿了,需要主人给宠物喂食
-
- 不同的宠物吃的东西不一样
- 不同的宠物吃的东西不一样
-
- 不同的宠物恢复后体力值不一样
狗狗类: 增加狗狗吃东西的方法。
企鹅类: 增加企鹅吃东西的方法。
创建主人类:
1、编写给狗狗喂东西的方法。
2、编写给企鹅喂东西的方法。
编写测试方法:
1、调用主人类给狗狗喂东西的方法。
2、调用主人类给企鹅喂东西的方法。
- 不同的宠物恢复后体力值不一样
那如果再领养XXX宠物,就需要给XXX喂食,怎么办?
- 添加XXX类,继承Pet类,实现吃食方法。
- 修改主人类,添加给XXX喂食的方法。
//主人类
public class Person {
public void feed(Dog dog){
dog.feed();
}
public void feed(Penguin penguin){
penguin.feed();
}
public void feed(XXX xxx){
xxx.feed();
}
... ...
//频繁修改代码,代码可扩展性、可维护性差。
}
//测试方法
... ...
Person person = new Person();
person.feed(dog);
person.feed(penguin);
person.feed(xxx);
//参数都是Pet类的子类
上述代码可否实现使用一个feed(Pet pet)实现对所有动物的喂食?
所以为了解决这个问题我们就需要使用接下来所学的多态来优化设计。
概念
对应同一个指令(调用同一个名称的方法),不同的对象给予不同的反应。(不同的方法实现)
多态的目的: 为了提高代码的扩展性和维护性,方便代码逻辑的编写。
二、多态的使用方法
- 使用多态实现思路
1、编写父类
2、编写子类,子类重写父类方法
3、运行时,使用父类的类型,子类的对象//向上转型 Pet pet = new Dog();
多态的两种表现形式:
1、父类作为方法参数。
2、父类作为方法的返回值类型。
使用父类作为方法形参实现多态
使用多态优化主人给宠物喂食
// 主人类
public class Person {
// 使用父类作为方法形参
public void feed(Pet pet){
pet.feed();
}
}
// 测试方法
... ...
Pet pet = new Dog();
Person person = new Person();
// 同一种操作方式,不同的操作对象
person.feed(pet);
... ...
使用父类作为方法返回值实现多态
使用多态实现领养宠物
- 使用父类作为方法返回值。
- 实现思路:
1、在Person类添加领养方法buyPet(int type)。
2、创建测试类,根据主人选择宠物类型编号来领养宠物。
// 主人类
public class Person {
// 使用父类作为返回值类型
public Pet buyPet(int type){
if(type == 1) {
return new Dog();
}else if (type == 2) {
return new Cat();
}else {
return new Penguin();
}
}
}
三、父类到子类的转换
- 实现主人与宠物玩耍功能
1、和狗狗玩接飞盘游戏,狗狗的健康值减少10,与主人的亲密度增加5。
2、和企鹅玩游泳游戏,企鹅的健康值减少10,与主人的亲密度增加5。 - 给Dog类添加接飞盘方法catchingFlyDisk()
- 给Penguin类添加游泳方法swimming()
- 给主人添加play(Pet pet)方法
// 狗狗类
public class Dog extends Pet{
public void catchingFlyDisk() {
System.out.println("和狗在玩接飞盘游戏,狗的健康值减少10,与主人的亲密度增加5");
}
}
// 企鹅类
public class Penguin extends Pet{
public void swimming() {
System.out.println("和企鹅玩游泳游戏,企鹅的健康值减少10,与主人的亲密度增加5");
}
}
// 主人类
public class Person {
public void play(Pet pet){
pet.catchingFlyDisk();
// 报错,父类引用不能调用子类特有方法
}
}
// 测试类
... ...
Pet pet = new Dog();
Person person = new Person();
person.play(pet);
为了解决上述问题我们就需要用到父类到子类的转换。
父类到子类的转换—向上转型
子类转换为父类,自动进行类型转换。
父类到子类的转换—向下转型
父类转换为子类,需要进行强制类型转换。
Pet pet = new Dog();
Dog dog = (Dog)pet;
Penguin penguin = (Penguin)pet;
// 报错,必须转换为父类指向的真实子类类型
- instanceof运算符
对象 instanceof 类或接口
// instanceof通常和强制类型转换结合使用
优化主人和宠物玩耍
// 主人类
public class Person {
public void play(Pet pet){
if (pet instanceof Dog){
Dog dog = (Dog) pet;
dog.catchingFlyDisk();
} else if (pet instanceof Penguin) {
Penguin penguin = (Penguin) pet;
penguin.swimming();
}
}
}
引用类型的转换
引用类型的转换跟基本数据类型的转换类似:
1、当父类需要转成子类的时候,要进行强制转换,但是在强制转换之前一定要先判断父类引用指向的子类对象到底是谁, 如果无法确定,在运行过程中可能会出错。
2、当子类需要向父类转换的时候,直接自动转换,不需要进行任何的判断。
四、小结
多态性是OOP中的一个重要特性,主要是用来实现动态联编的,换句话说,就是程序的最终状态只有在执行过程中才被决定而非在编译期间就决定了。这对于大型系统来说能提高系统的灵活性和扩展性。
- 引用变量的两种类型:
1、编译时类型(模糊一点,一般是父类):由声明时的类型决定。
2、运行时类型(运行时,具体是哪个子类就是哪个子类):由实际对应的对象类型决定。 - 多态的存在要有3个必要条件:
1、必须要有继承关系。
2、子类方法必须重写父类的方法。
3、父类引用指向子类对象。
如果需要完整代码可以点击次链接到gitee仓库中: 多态