当前位置: 首页 > news >正文

Java继承和多态(2)

🐵本篇文章将对多态的相关知识进行讲解


一、向上转型

向上转型是实现多态的条件之一;向上转型是让子类对象转换为父类对象或者是让父类的引用指向子类对象,直观的表现形式就是将子类的对象赋值给父类对象的引用;下面讲解向上转型的三种形式

1.1 直接赋值

class Animal { }
class Dog extends Animal { }public class Test {public static void main(String[] args) {Animal animal = new Dog(); //向上转型}
}

1.2 传参

class Animal {}
class Dog extends Animal {}public class Test {public static void func(Animal animal) { //发生向上转型animal.eat();}public static void main(String[] args) {Dog dog = new Dog();func(dog); //将Dog对象传过去,在func方法中用父类对象接收}
}

1.3 返回值

class Animal {}
class Dog extends Animal {}public class Test {public static Animal func() { return new DOg(); //发生向上转型}public static void main(String[] args) {Dog dog = new Dog();func(); }
}

注意:向上转型后父类对象并不能访问子类中特有的成员方法

1.4 向下转型

直接看代码:

class Animal {public void eat() {System.out.println("吃");}
}class Dog extends Animal {public void eat() {System.out.println("狗在吃");}public void barks() {System.out.println("狗在叫");}
}public class Test {public static void main(String[] args) {Animal animal = new Dog();animal.eat();//animal.barks();//向上转型后,animal也不能访问子类独有的成员方法,但是可以进行向下转型Dog dog = (Dog) animal; //将父类对象强转为子类对象dog.barks(); //此时就可以访问子类独有的成员方法}
}

向下转型也存在一些危险,在上述代码的基础上再增加一个鸟类:

class Animal {public void eat() {System.out.println("吃");}
}class Dog extends Animal {public void eat() {System.out.println("狗在吃");}public void barks() {System.out.println("狗在叫");}
}class Bird extends Animal {public void fly() {System.out.println("鸟在飞");}public void eat() {System.out.println("鸟在吃");}
}public class Test {public static void main(String[] args) {Animal animal = new Dog();Bird bird = (Bird) animal;bird.fly(); //编译不会报错,但在运行时会报错,//因为animal实际引用的是一个狗的对象,只能强转为一个狗类//为了避免这种情况的发生,引入instanceof关键字if (animal instanceof Bird) { //这条语句的意思就是animal所指的对象是否为鸟类Bird bird1 = (Bird) animal;bird1.flu //运行时不会报错}}
}

二、方法的重写

方法的重写也是也是实现多态的条件之一,重写也叫覆盖,方法的重写发生在继承关系下,一般称作子类对父类的方法进行重写,即在子类中再写一个方法,这个方法必须和父类那个方法的方法名、参数列表、返回值类型相同;这里可以和方法的重载比较理解

重载:方法名相同,参数列表不同,与返回值类型无关

重写:方法名相同,参数列表相同,返回值类型相同

class Animal {public void eat() {System.out.println("吃");}
}class Dog extends Animal {//重写的方法可以用@Override来注释,这样在编译时可以多一层校验//如果加上这条注释后,eat方法没有进行重写,那么在编译时就会报错@Overridepublic void eat() { //方法名都为eat,返回值类型都为void,参数列表相同System.out.println("狗在吃");}
}

2.1 重写的注意事项

1. 被final修饰的方法叫做密封方法,此方法不能被重写

class Animal {public final void eat() {System.out.println("吃");}
}class Dog extends Animal {@Overridepublic void eat() {System.out.println("狗在吃");}
}//编译会报错,因为父类eat方法被final修饰,eat方法不能被重写

2. 被static修饰的方法不能被重写

3. 子类重写父类方法时,子类方法的访问限定修饰符必须大于等于父类方法,但如果父类方法被private修饰,那么该方法就不能被重写

4. 重写的方法的返回值类型也可以不同,但必须构成父子类关系

class Animal {public Animal eat() {System.out.println("吃");return null; //这里是为了不报错才这么写的}
}class Dog extends Animal {@Override public Dog eat() {System.out.println("狗在吃");return null;}
}

2.2 动态绑定

当一个子类对象被转换为了父类对象(向上转型),如果该对象调用一个在子类中被重写的父类方法,Java会根据子类的实际类型来调用子类对象实际所属类的方法,这个过程叫做动态绑定,动态绑定并不是在编译时就知道调用哪一个方法,而是在运行时才知道真正要调用哪一个方法

2.3 构造方法中避免调用重写方法

在构造方法中如果调用重写方法也会发生动态绑定

class B {public B() {func(); //这里会调用子类的func方法}public void func() {System.out.println("B.func()");}
}
class D extends B {private int num = 1;@Overridepublic void func() {System.out.println("D.func() " + num); //这里打印的num为0}
}public class Test2 {public static void main(String[] args) {D d = new D();}
}

为什么num打印结果为0?先来回顾以下的执行顺序

父类静态--->子类静态--->父类实例--->父类构造--->子类实例--->子类构造

在上述代码中完成父类构造后,直接调用func方法,没有执行子类实例,也就是此时num并没有被赋值,是默认值0

三、多态

多态就是一个父类引用在调用重写的方法时,根据引用所指的对象不同,而调用的不同的方法,以下面的代码为例:

class Animal {public void eat() {System.out.println("吃");}
}class Dog extends Animal {public void eat() {System.out.println("狗在吃");}
}class Bird extends Animal {public void eat() {System.out.println("鸟在吃");}
}public class Test {public static void func(Animal animal) {animal.eat(); //我们称在这里发生了多态}public static void main(String[] args) {Dog dog = new Dog();Bird bird = new Bird();func(dog);func(bird);}
}

总结:必须向上转型后才能实现动态绑定,通过动态绑定调用子类重写方法,而多态完成了很多次的动态绑定

3.1 多态的好处

1. 可以避免代码中的圈复杂度(即代码中条件语句和循环语句出现的次数)

2. 可扩展性强

class Shape {public void draw() {System.out.println("画图形");}
}class Cycle extends Shape {@Overridepublic void draw() {System.out.println("圆形");}
}class Rect extends Shape {@Overridepublic void draw() {System.out.println("矩形");}
}class Triangle extends Shape {@Overridepublic void draw() {System.out.println("三角形");}
}
public class Test2 {public static void main(String[] args) {Cycle cycle = new Cycle();Rect rect = new Rect();Triangle triangle = new Triangle();Shape[] shapes = new Shape[]{cycle, rect, cycle,rect,triangle}; //发生向上转型for(Shape shape: shapes) {shape.draw(); 发生多态,如果不使用多态,就要用到大量if-else,使代码的圈复杂度提高}//结果为:圆形 矩形 圆形 矩形 三角形}
}

相关文章:

  • 手撕无头单链表
  • YOLOv5项目实战(3)— 如何批量命名数据集中的图片
  • 代码随想录算法训练营Day 53 || 1143.最长公共子序列、1035.不相交的线、53. 最大子序和
  • 【T690 之十一】基于方寸EVB2开发板,结合 Eclipse+gdb+gdbserver 调试 CCAT 的流程总结
  • 场景图形管理-多视图多窗口渲染示例(4)
  • redis高级案列case
  • 二十七、W5100S/W5500+RP2040树莓派Pico<iperf 测速示例>
  • 【数据处理】Python:实现求条件分布函数 | 求平均值方差和协方差 | 求函数函数期望值的函数 | 概率论
  • 相机通用类之LMI激光三角相机(3D),软触发硬触发(飞拍),并输出halcon格式对象
  • Linux命令--重启系统的方法
  • 电源电压范 围宽、功耗小、抗干扰能力强的国产芯片GS069适用于电动工具等产品中,采用SOP8的封装形式封装
  • Redis缓存穿透、击穿、雪崩
  • 阿里云国际站:密钥管理服务
  • 【Vue原理解析】之异步与优化
  • python接口自动化-参数关联
  • 0基础学习移动端适配
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • 5、React组件事件详解
  • Github访问慢解决办法
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • Javascripit类型转换比较那点事儿,双等号(==)
  • js算法-归并排序(merge_sort)
  • k8s如何管理Pod
  • Linux快速复制或删除大量小文件
  • OSS Web直传 (文件图片)
  • Python3爬取英雄联盟英雄皮肤大图
  • Sass 快速入门教程
  • spring cloud gateway 源码解析(4)跨域问题处理
  • SQLServer之创建数据库快照
  • 包装类对象
  • 不上全站https的网站你们就等着被恶心死吧
  • 大主子表关联的性能优化方法
  • 当SetTimeout遇到了字符串
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 解决iview多表头动态更改列元素发生的错误
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 聊一聊前端的监控
  • 判断客户端类型,Android,iOS,PC
  • 前嗅ForeSpider采集配置界面介绍
  • 使用agvtool更改app version/build
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 小程序开发中的那些坑
  • 译有关态射的一切
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • 国内开源镜像站点
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • !$boo在php中什么意思,php前戏
  • # 达梦数据库知识点
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • (007)XHTML文档之标题——h1~h6