多态
需求分析
养了多只动物, 每一个动物生病之后, 需要提供相应的方法 ,
给宠物看病, 宠物越多, 方法越多 , 每添加一个宠物, 就需要添加一个方法
弊端: 频繁修改代码, 可扩展性和可维护性差
// 给狗看病的方法
public void cure(Dog dog){
System.out.println("给"+dog.name+"看病 ");
}
// 给猫看病
public void cure(Cat cat){
System.out.println("给"+cat.name+"看病 ");
}
//给猪看病
public void cure(Pig pig){
System.out.println("给"+pig.name+"看病 ");
}
优化之后
// 给动物看病的方法
public void cure(Animal animal){
System.out.println("给"+animal.name+"看病 ");
}
多态的使用
父类的变量 指向 子类的对象
Animal animal = new Dog(); // Dog dog = new Dog();
回顾基本数据类型
int a = 10;
long b = a;
作用案例
参数列表是父类的情况
Person person= new Person();
Dog dog = new Dog();
dog.name = "旺财";
// 人给动物看病
person.cure(dog);
Cat cat = new Cat();
cat.name = "Tom";
// 人给动物看病
person.cure(cat);
返回值为父类的情况(人去买宠物)
// 客户 需要告诉商家 要买什么宠物
public Animal sell(String type){
if(type.equals("dog")){
Dog dog = new Dog();
dog.name = "来福";
return dog;
}else if(type.equals("cat")){
Cat cat = new Cat();
cat.name = "hello kitty";
return cat;
}else{
Pig pig = new Pig();
pig.name = "佩琪";
return pig;
}
}
优势好处
屏蔽子类之间的差异
可替换性
可扩充性
接口性
灵活性
简化性
多态注意事项
父类变量指向子类对象
儿子装爹案例
父亲 是 中医大夫
儿子 学习 西医
( 有人来看病- 该病人相信中医大夫, 但是恰好中医大夫不在家, 只有儿子在家 )
儿子装爹
新建father类
package date0712;
/**
* 中医大夫 (父亲)
*/
public class Father {
// 姓名
String name = "扁鹊";
// 年龄
int age = 100;
// 工具包 = 针灸包
String instrument = "acupuncture";
// 爱好
String hobby = "喝茶";
// 有瓷器(父亲有 儿子没有)
String china = "景德镇";
// 娱乐活动
public void play(){
System.out.println("喝茶,看报,听曲 !");
}
// 看病的方法
public void cure(){
System.out.println("望闻问切 ");
System.out.println("使用中药, 针灸 治疗");
}
// 把脉的方法 (父亲有 儿子没有 , 儿子会默认继承)
public void pulse(){
System.out.println("把脉");
}
}
新建 son子类
package date0712;
/**
* 西医 (儿子)
*/
public class Son extends Father{
// 姓名
String name = "扁小鹊";
// 年龄
int age = 25;
// 工具包 = 针灸包
String instrument = "手术刀";
// 爱好
String hobby = "刷抖音,玩游戏";
// 电脑 (儿子有 父亲没有)
String computer = "苹果";
// (父类有play 方法, 如果儿子自己没有play 默认继承父类的)
// 方法重写 父类有该方法, 但是 儿子偏偏不喜欢 ()
@Override
public void play(){
System.out.println("逛夜店, 蹦迪!");
}
// 看病的方法
@Override
public void cure(){
System.out.println("听诊器 先进设备查一查 ");
System.out.println("使用西药,做手术");
}
// 做手术 (儿子有 父亲没有)
public void operate(){
System.out.println("做手术");
}
}
方法和属性的调用
public class Demo {
public static void main(String[] args) {
// 病人上门 找 中医 , 只有西医儿子在家
// 儿子穿上父亲的衣服 模拟父亲的外貌
Father father = new Son();
System.out.println(father.name);
System.out.println(father.age);
System.out.println(father.instrument);
System.out.println(father.hobby);
System.out.println(father.china);
/*
对于属性 父亲有什么 , 儿子才能有什么 (儿子只能使用父亲有的东西)
方法 父亲有什么方法, 儿子才能使用什么方法
*/
// System.out.println(father.computer); //报错
father.pulse();
// father.operate(); // 手术方法 报错
// 编译看左边 编译不报错, 需要看赋值号左侧 类型中有那些属性和方法
// 运行看右边 当子类重写了父类的方法之后 , 运行实际对象重写之后的方法
father.play();
father.cure();
}
}
编译看左边 编译不报错, 需要看赋值号左侧 类型中有那些属性和方法
运行看右边 当子类重写了父类的方法之后 , 运行实际对象重写之后的方法
对象的向上和向下转型
// 先卸下父亲的伪装 , 还原儿子的真面貌 , 才可以去调用儿子的属性和方法
Father father = new Son();
Son son = (Son) f1;
儿子 ==> 父亲 向上转型 (由小容器到大容器 ) 多态
父亲 ==> 儿子 向下转型 (由大容器到小容器) 需要先判断 然后在转型
instanceof
新建女儿类
public class Daughter extends Father{}
Father f1 = new Son();
Father f2 = new Daughter();
Son son = (Son) f1;
Daughter daughter = (Daughter) f2;
// 儿子和女儿之间不能 转换 (否则会报类型转换异常)
// java.lang.ClassCastException
避免类型转换异常
// 判断 f1 对象 是否可以转换为 Son 对象
System.out.println(f1 instanceof Son);