目录
1.多态的基础语法
1.什么是多态?
不同的子类在继承父类后分别都重写覆盖了父类的方法,即父类同一个方法,在继承的子类中表现出不同的形式。
2.多态的前提条件
- 子类与父类有继承关系
- 要有方法重写
- 有父类引用指向子类对象
3. 多态的类型转型
1.向上转型
1.语法结构:
父类类型 引用名 = new 子类类型();
//右侧创建一个子类对象,把它转换为父类类型的对象,这是自动转换
2.注意:
- 编译类型看左边,运行类型看右边
- 可以调用父类的所有成员(需遵守访问权限)
- 不能调用子类的特有成员
结合代码理解上面的注意点
package 集成开发.多态;
public class Animal {
String abc;
public void some(){
System.out.println("动物在动");
}
public void fun(){
System.out.println("动物们都很快乐");
}
}
class Cat extends Animal{
String df;
public void some(){
System.out.println("猫在走猫步");
}
public void move(){
System.out.println("猫在抓老鼠");
}
}
class Bird extends Animal{
public void some(){
System.out.println("鸟儿在飞");
}
}
class text{
public static void main(String[] args) {
//编译类型看左边,运行类型看右边
Animal am=new Cat();
//编译时编译器只认识am变量是一个Animal类型,这里将Cat类型转换为Animal类型是自动转换
am.some();
/*你以为这里是"动物在动"?实际上这里返回的是"猫在走猫步",因为虽然在编译阶段am是一个Animal类型的引用
但是在运行阶段因为am的底层其实是一个Cat类型的对象,所以调用的是Cat的some方法*/
//可以调用父类的所有成员
am.abc="123";
am.fun();//动物们都很快乐
//不能调用子类的特有成员
am.move();
//!报错,因为此时的am是Animal对象,move方法是Cat类独有的方法,且Animal类没有move方法
}
}
2.向下转型
1.语法格式:
子类类型 引用名 = (子类类型) 父类引用;
//用强制类型转换的格式,将父类引用类型转为子类引用类型
2.注意
- 只有向上转型后的才可以向下转型
- 向下转型容易出现Exception in thread "main" java.lang.ClassCastException异常报错【编译没有出错,但是运行会报错】
- 向下转型多用于需要访问子类的独有方法时候才向下转型
结合代码理解上面的注意点
package 集成开发.多态;
public class Animal {
String abc;
public void some(){
System.out.println("动物在动");
}
public void fun(){
System.out.println("动物们都很快乐");
}
}
class Cat extends Animal{
String df;
public void some(){
System.out.println("猫在走猫步");
}
public void move(){
System.out.println("猫在抓老鼠");
}
}
class text{
public static void main(String[] args) {
//只有向上转型后的子类才可以向下转型
Animal am=new Cat();
Cat cat=(Cat)am;
//move是cat的独有方法
cat.move();//猫在抓老鼠
//这里没有先向上转型,直接向下转型。编译阶段不会报错,运行阶段这里报错Exception in thread "main" java.lang.ClassCastException
Cat cat2=(Cat)new Animal();
}
}
3.向下转型经典异常报错
package 集成开发.多态;
public class Animal {
public void some(){
System.out.println("动物在动");
}
}
class Cat extends Animal{
public void some(){
System.out.println("猫在走猫步");
}
public void move(){
System.out.println("猫在抓老鼠");
}
}
class Bird extends Animal{
public void some(){
System.out.println("鸟在飞");
}
}
class text{
public static void main(String[] args) {
Animal am=new Bird();
Cat cat=(Cat)am;//编译不会报错,运行报错Exception in thread "main" java.lang.ClassCastException
}
}
4.使用instanceof操作符避免异常报错
1.instanceof的语法格式
语法格式:
引用 instanceof 数据类型
返回值:
true: 代表这个引用指向的对象是这个数据类型
false:代表这个引用指向的对象是这个数据类型
例如:
a instanceof String;
如果返回真表示a是一个String类型对象
如果返回假表示a不是一个String类型对象
2.实例演示
package 集成开发.多态;
public class Animal {
public void some(){
System.out.println("动物在动");
}
}
class Cat extends Animal{
public void some(){
System.out.println("猫在走猫步");
}
public void move(){
System.out.println("猫在抓老鼠");
}
}
class Bird extends Animal{
public void some(){
System.out.println("鸟在飞");
}
}
class text{
public static void main(String[] args) {
Animal am=new Cat();
if(am instanceof Cat){
Cat cat=(Cat)am;
cat.some();
}else{
Bird bi=(Bird) am;
bi.some();
}
//输出结果为:猫在走猫步
}
}
2.多态在实际开发中作用思想指导【代码+详解】
首先我们来假设一个场景,主人投食宠物,宠物接受投食吃东西,在不看下面代码之前,尝试自己写一下这个程序
public class Text {
public static void main(String[] args) {
//创建主人对象
zhuRen ren=new zhuRen();
//创建小狗对象
dog dg=new dog();
//主人对小狗投食,小狗吃骨头
ren.feed(dg);//小狗正在啃骨头
}
}
class zhuRen{
public void feed(dog d){
d.eat();
}
}
class dog{
public void eat(){
System.out.println("小狗正在啃骨头");
}
}
此时我们又养了养了一只猫,这只猫主人也可以对它进行投食,猫也可以接受投食吃东西,显然为了满足这个需求,我们需要对上面主人的feed方法进行重载,通过传入不同的宠物类型,给不同的宠物投食
package 集成开发;
public class Text {
public static void main(String[] args) {
//创建主人对象
zhuRen ren=new zhuRen();
//创建小狗对象
dog dg=new dog();
//主人对小狗投食,小狗吃骨头
ren.feed(dg);
//创建小猫对象
Cat cat=new Cat();
//小猫接受投食吃鱼
ren.feed(cat);//小猫正在吃鱼
}
}
class zhuRen{
public void feed(dog d){
d.eat();
}
//对feed方法针对cat进行重载
public void feed(Cat cat){
cat.eat();
}
}
class dog{
public void eat(){
System.out.println("小狗正在啃骨头");
}
}
class Cat{
public void eat(){
System.out.println("小猫正在吃鱼");
}
}
试想以下,如果我们后面养了越来越多的宠物,那么每增加一个宠物就要对主人的feed投食方法进行重载,每次都要更改我们的主程序,这样的作法导致我们的主程序的包容性非常的差,如果主程序中有大量的代码和复杂的逻辑关系,那么每进行一次增加就意味着主程序要进行新的测试,这样势必会增加软件的开发成本,那么我们下面采用Java的多态机制对上面的代码进行优化,创建一个新的Pet类,所有的宠物都继承它,将主人的feed方法面向这个Pet类型的对象,每增加一个新的宠物,将这个宠物强制转换成Pet类型,然后不同的宠物调用实际上是自己底层的eat方法
package 集成开发;
public class Text {
public static void main(String[] args) {
//创建主人对象
zhuRen ren=new zhuRen();
//创建小狗、小猫对象,然后向上转型成Pet类型
dog dg=new dog();
Pet dog=dg;
Cat ct=new Cat();
Pet cat=ct;
//然后主人投食
ren.feed(dog);//小狗正在啃骨头
ren.feed(cat);//小猫正在吃鱼
注释:我们定义了一个新的宠物类Pet,主人在调用投食feed的时候面向的对象是Pet类型,把所有
的猫、狗等动物都继承Pet类型,然后向上转型都转换成Pet类型,当我们主人在调用feed()方法时候,
如果向里面传入的是cat的向上转型,那么底层任然是cat类型,如果传入的是dog的向上转型,
那么底层任然是dog类型,他们任然会调用自己的eat方法
}
}
class zhuRen{
public void feed(Pet d){
d.eat();
}
}
class Pet{
public void eat(){
}
}
class dog extends Pet{
public void eat(){
System.out.println("小狗正在啃骨头");
}
}
class Cat extends Pet{
public void eat(){
System.out.println("小猫正在吃鱼");
}
}