java基础_多态

java基础_多态

什么是多态?
多种形态,多种状态。具体指:编译的时候一种形态,运行的时候另一种形态。
指的是父类型的引用指向子类型的对象。编译阶段:静态绑定父类的方法;运行阶段:动态绑定子类型对象的方法。

学习多态前需要了解两个基本概念:向上转型(子转父)、向下转型(父转子)。
注意: 在java语法中既允许向上转型,也允许向下转型。但无论是向上转型还是向下转型都必须要有继承关系,两者之间没有继承关系,编译报错(这句话不适用于接口之间)。

什么时候需要用到向下转型?
不要随便进行类型转换,当你所需要访问的方法是子类特有的,此时必须使用向下转型!

案例代码

父类:Animal.class

// 动物类:父类
public class Animal{
	// 移动的方法
	public void move(){
		System.out.println("动物在移动!");
	}
}

子类:Cat.class

// 猫类,子类
public class Cat extends Animal{
	// 对move方法进行重写
	public void move(){
		System.out.println("cat走猫步!");
	}
	// 猫除了move之外,应该有自己特有的行为,例如抓老鼠。
	// 这个行为是子类型对象特有的方法。
	public void catchMouse(){
		System.out.println("猫正在抓老鼠!");
	}
}

子类:Brid.class

// 鸟类,子类
public class Brid extends Animal{
	// 对move方法进行重写
	public void move(){
		System.out.println("Brid在飞翔!");
	}
}

测试类:Test.class

public class Test{
	public static void main(String[] args){
		Animal a1 = new Cat(); //父类型的引用指向了子类型的对象
		a1.move();   //输出结果:cat走猫步!

	//===注意:a1与a2两个实例是分开测试的,a1可以编译通过===
		Animal a2 = new Cat(); //父类型的引用指向了子类型的对象
		a2.catchMouse();   //编译报错,找不到符号
	}
}

输出结果分析

一、a1.move() 为什么输出结果为:cat走猫步! 而不是 动物在移动!
java程序分为编译阶段和运行阶段。
先来分析编译阶段:
对于编译器来说,编译器只知道a1的类型是Animal,所以编译器在检查语法的时候,会去Animal.class字节码文件中找move()方法,找到了,绑定上move()方法,编译通过,静态绑定成功。(编译阶段属于静态绑定。)
再来分析运行阶段:
运行阶段的时候,实际上在堆内存中创建的java对象是Cat对象,所以move的时候,真正参与move的对象是一只猫,所以运行阶段会动态执行Cat对象的move()方法。这个过程属于运行阶段绑定。(运行阶段绑定属于动态绑定。)
编译的时候一种形态,运行的时候另一种形态。这就是多态。

二、a2.catchMouse() 为什么编译报错?
对于编译器来说,编译器只知道a2的类型是Animal,所以编译器在检查语法的时候,会去Animal.class字节码文件中找catchMouse()方法,结果没有找到,静态绑定失败,编译报错。
三、如何解决a2非要调用catchMouse()的编译报错问题?
这个时候必须要使用 向下转型。
a2是Animal类型,强制转换为了Cat类型,Animal与Cat之间存在继承关系,所以不会报错。这里是从 Animal–> Cat (父类到子类)向下转型。

Animal a2 = new Cat();
Cat cat = (Cat)a2;  // (Cat)是强制类型转换符
cat.catchMouse();  //输出结果:猫正在抓老鼠!

向下转型有风险吗?

//观察这段测试代码
Animal a3 = new Brid(); 
Cat cat = (Cat)a3; 
cat.catchMouse(); //java.lang.ClassCastException:类型转换异常。

编译通过运行报错,java.lang.ClassCastException:类型转换异常。
编译阶段:编译器检测a3是Animal类型,而Animal与Cat存在继承关系,所以可以向下转型,编译通过。运行阶段:堆内存实际创建的对象是:Brid对象,在实际运行的过程中,拿着Brid对象转换成Cat对象就不行了,应为Brid和Cat之间不存在继承关系。

怎么避免ClassCastException异常发生?
通过 instanceof 关键字,可以动态判断引用指向的对象的类型。
在java规范中,对类型进行向下转型时,一定要使用 instanceof 运算符进行判断。

Animal a3 = new Brid(); 
System.out.println(a3 instanceof  Cat);  // false
if(a3 instanceof  Cat){  //如果a3是一只猫
  Cat cat = (Cat)a3; 
  cat.catchMouse();   //编译通过、运行通过,因为压根不执行
}

instanceof 语法:
语法格式: 引用 instanceof 类型
instanceof 运算符的运算结果只能是 true / false

案例:c是一个引用,c变量保存了内存地址指向了堆内存中的对象。
假设 (c instanceof Cat)为true 表示:c引用指向的堆内存中的java对象是一个Cat。
假设 (c instanceof Cat)为false表示:c引用指向的堆内存中的java对象不是一个Cat。

实现多态的条件:
1、继承:必须要有子类继承父类的继承关系。
2、重写:子类需要对父类中的一些方法进行重写,然后调用方法时就会调用子类重写的方法而不是原本父类的方法。
3、向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。

多态的作用:
降低程序的耦合度,提高程序的扩展力。
使程序符合OCP(开闭)原则,对扩展开放,对修改关闭。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值