写在开头
Java语言的三大特点之一:多态
多态是同一个行为具有多个不同表现形式或形态的能力。
事物的多种形态,父类引用指向子类对象
今天我们说一下这一个比较晦涩难懂的概念
概念
事物的多种形态
- 举例:猫是猫,但猫也是动物,猫这个类就具有多种形态
- 发生的前提 :必须有子父类继承关系或者接口实现关系;子类必须重写父类方法
- 表现方法:父类引用指向子类对象
1 | Animal 类,父类 |
多态中成员变量的优先级
多态中成员变量的规则: 编译看=的左边(父类),运行看=的左边(父类)
编译: 指就是写代码的过程,如果父类中,没有这个成员变量,于是代码编译就会报错
运行: 指代码在内存中运行时,成员变量,调用的实际上是父类中的成员
(Animal a = new Cat(); 在调用成员变量时,a想象成super)
1 | // 多态中的子类,Cat |
1 | // 多态中的父类 |
1 | // 测试多态 |
多态中的方法 ⭐
多态中方法的规则: 编译看=的左边(父类),运行看=的右边(子类重写)
编译: 如果父类中,没有这个方法,那么编译就会报错
运行: 运行子类中的重写方法(如果子类中没有重写,调用父类中的方法)
1 | // 多态中的子类,Dog |
1 | // 多态中的父类 |
1 | // 测试多态 |
多态在内存中的运行
多态中的静态方法
多态中静态方法的规则: 编译看=的左边(父类),运行看=的左边(父类)
编译: 如果父类中,没有这个静态方法,那么编译就会报错
运行: 运行父类中的静态方法
原因: 静态属于类,不属于类的任何对象,因此Animal中的静态方法,与Animal等号右边的对象是谁,无关.
1 | // 多态中的父类 |
1 | // 多态中的子类,Dog |
1 | // 测试多态 |
多态的转型
向上向下转型
向上转型
父类的引用指向子类的对象(Cat是Animal的子类)
Animal a = new Cat();Cat小辈,转换成长辈的应用,年龄大了,向上转型(自动)
局限: 只能调用子父类中,共有的成员变量或者成员方法向下转型
Cat c = (Cat)父类的引用;// 子类对象 变量名 = (子类对象) 父类变量
举例: Cat c = (Cat)a;
现在,由父类的引用转换成了子类自己的对象,c可以调用Cat类中的所有成员(包括与父类相同的方法,也包括子类特有方法)
Animal长辈,转换成Cat小辈,年龄小了,向下转型(强制类型转换)
举一个比较好理解的栗子:
我和我的父亲,我是一名java老师,我的父亲也是一名老师,但是父亲讲的是社会学理论
我和父亲之前存在着子父类关系,我继承了父亲的技能,但是又重写了父亲的技能
有一天父亲的学生来找父亲去演讲,父亲不在家,我假扮成父亲代父亲去参加演讲,这就是向上转型
我只能使用我和父亲相同的功能,父亲的演讲的技能我不能够使用
回到家后,我的朋友来找我,想约我去看电影,但是父亲的技能里没有看电影这个技能,然后我就脱掉衣服转成我自己原本的形态这就是向下转型
1 | // 多态中的子类,Dog |
1 | // 多态中的父类 |
1 | // 测试多态 |
向下转型的注意事项
多态中进行向下转型之前,先判断,父类的引用是否可以转换成子类的对象
instanceof :
instanceof 用法 : 父类的引用 instanceof 子类的对象
判断这个父类的引用,能否转换成对应的子类
instanceof 结果: boolean 类型,如果返回true,证明可以转型;返回false,不能转型
为什么使用instanceof ,因为向下转型时,如果类型不一致,编译不会报错,运行时会报出异常,运行时期的异常属于代码隐患,需要在编译环节尽量祛除
1 | // 测试多态 |
多态的好处
- 多态代码的扩展性很好
- 定义一个方法时,将方法的参数,设置成一个父类(形式参数),方法实际调用的时候所传的参数,可以是父类类型,也可以是任意的子类类型(多态的使用)
- 定义一个方法时,将方法的返回值,设置成一个父类,方法实际返回的时候,可以返回父类类型,也可以是任意的子类类型(多态的使用)
Animal父类 eat();
Cat 子类 重写eat();
Dog子类 重写eat();
定义一个方法:
方法的要求: 传入不同的参数,能让不同的动物吃不同的食物
public void animalEat(Animal a){// 实际调用 new Cat(); new Dog();
a.eat();
}
1 | // 多态中的子类,Cat |
1 | // 多态中的子类,Dog |
1 | // 多态中的父类 |
1 | // 多态的好处 |
1 | // 测试多态 |
晚安
今天就到这里了,明天见,加油!