Java三大特性之多态详解
作者:共饮一杯无 发布时间:2022-11-07 14:24:40
概述
引入
多态是继封装、继承之后,面向对象的第三大特性。 生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。
定义
多态: 是指同一行为,具有多个不同表现形式。
多态的体现
多态体现的格式:
父类类型 变量名 = new 子类对象; 变量名.方法名();
父类类型:指子类对象继承的父类类型,或者实现的父接口类型。 代码如下:
Fu f = new Zi();
f.method();
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后方法。 代码如下: 定义父类:
public abstract class Animal {
public abstract void eat();
}
定义子类:
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼??");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头??");
}
}
定义测试类:
public class Test {
public static void main(String[] args) {
// 多态形式,创建对象
Animal a1 = new Cat();
// 调用的是 Cat 的 eat
a1.eat();
// 多态形式,创建对象
Animal a2 = new Dog();
// 调用的是 Dog 的 eat
a2.eat();
}
}
多态的好处
实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利。代码如下: 定义父类:
public abstract class Animal {
public abstract void eat();
}
定义子类:
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼??");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头??");
}
}
定义测试类:
public class Test {
public static void main(String[] args) {
// 多态形式,创建对象
Cat c = new Cat();
Dog d = new Dog();
// 调用showCatEat
showCatEat(c);
// 调用showDogEat
showDogEat(d);
/**
以上两个方法, 均可以被showAnimalEat(Animal a)方法所替代
而执行效果一致
*/
showAnimalEat(c);
showAnimalEat(d);
}
public static void showCatEat (Cat c){
c.eat();
}
public static void showDogEat (Dog d){
d.eat();
}
public static void showAnimalEat (Animal a){
a.eat();
}
}
由于多态特性的支持,showAnimalEat方法的Animal类型,是Cat和Dog的父类类型,父类类型接收子类对象,当然可以把Cat对象和Dog对象,传递给方法。 当eat方法执行时,多态规定,执行的是子类重写的方法,那么效果自然与showCatEat、showDogEat方法一致, 所以showAnimalEat完全可以替代以上两方法。 不仅仅是替代,在扩展性方面,无论之后再多的子类出现,我们都不需要编写showXxxEat方法了,直接使用 showAnimalEat都可以完成。 所以,多态的好处,体现在,可以使程序编写的更简单,并有良好的扩展。
引用类型转换
多态的转型分为向上转型与向下转型两种:
向上转型
向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。 当父类引用指向一个子类对象时,便是向上转型。 使用格式:
父类类型 变量名 = new 子类类型(); 如:Animal a = new Cat();
向下转型
向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。 一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。 使用格式:
子类类型 变量名 = (子类类型) 父类变量名; 如:Cat c =(Cat) a;
为什么要转型
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。 转型演示,代码如下: 定义类:
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼??");
}
public void catchMouse() {
System.out.println("抓老鼠??");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头??");
}
public void watchHouse() {
System.out.println("看家??");
}
}
定义测试类:
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
}
转型的异常
转型的过程中,一不小心就会遇到这样的问题,请看如下代码:
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse 【运行报错】
}
}
这段代码可以通过编译,但是运行时,却报出了 ClassCastException ,类型转换异常!这是因为,明明创建了Cat类型对象,运行时,当然不能转换成Dog对象的。这两个类型并没有任何继承关系,不符合类型转换的定义。为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:
变量名 instanceof 数据类型 如果变量属于该数据类型,返回true。 如果变量不属于该数据类型,返回false。
所以,转换前,我们最好先做一个判断,代码如下:
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
if (a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
} else if (a instanceof Dog){
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse
}
}
}
来源:https://juejin.cn/post/7153062744193777677


猜你喜欢
- 在Controller层时,往往会需要校验或验证某些操作,而在每个Controller写重复代码,工作量比较大,这里在Springboot项
- 前言LocalDateTime、LocalDate、LocalTime 是 Java8 全新的日期框架,加强了对时间的管理,有很多特别好用的
- 快速回顾1.Lambda表达式: (参数) -> {主体}Lambda表达式打开了函数式编程爱好者继续使用Java的大门。Lambda
- Android设备用久了,截屏是个麻烦事。更麻烦的是通过qq传到电脑上,倒腾半天。其实用adb命令就可以截屏,然后写个pull的语句就可以拉
- 本文实例讲述了JAVA随机打乱数组顺序的方法。分享给大家供大家参考。具体实现方法如下:import java.util.Random;&nb
- Android自定义View仿探探卡片滑动这种效果网上有很多人已经讲解了实现思路,大多都用的是RecyclerView来实现的,但是我们今天
- 使用AES算法可用于对数据进行加密码与解密,使用的时候需要注意两点:1)被加密的串越长,加密后的字符串越长,注意数据库字段的设计;2)Lin
- Android 动画实现几种方案在 Android 的 FrameWork 中,为我们提供三种动画的实现方式:逐帧(Frame)动画、视图/
- 三层架构将整个业务应用划分为:(1)界面UI层(2)业务逻辑层(3)数据访问层对于复杂的系统分层可以让结构更加清晰,模块更加独立,便于维护。
- 一、指标监控引入jar包: <dependency> &nb
- cookie和session的比较一、对于cookie:①cookie是创建于服务器端②cookie保存在浏览器端③cookie的生命周期可
- 简介:gateway主要是做路由 负载,过滤 主要是替代zuul 1.x 性能比zuul好 zuul是基于Servlet ,gateway是
- Java常用类包装类由于Java语言中的基本类型不是面向对象,并不具备对象的性质,实际使用存在很多不便。Java在java.lang包中提供
- 最近有个同事在调用一个类库中的方法时遇到了一个问题,异常信息如下:尝试释放正在使用的RCW,活动线程或其他线程上正在使用该 RCW,释放正在
- 之前知道spring支持JSR校验,在自己定义的bean中加入@NotNull,@NotBlank,@Length等之类的校验用于处理前台传
- 本文实例为大家分享了AJAX二级联动效果的具体代码,供大家参考,具体内容如下Ajax.jsvar createAjax = function
- 前言目前,企业项目的开发过程中,往往会使用配置文件来做一些配置项来实现项目部署的灵活性,避免硬编码的方式在环境变化时需要对代码进行重新编译。
- MyBatisMyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC
- 今天接触了一下ToStringBuilder类,这里做一个备忘。ToStringBuilder在包 common-lang 中,主要用于一个
- 对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yue)一起经过特殊加密算法处理