【方法重写】精英必看:详解Java中的方法重写!!

前言

当我在学到“面向对象”这块内容的时候,学到了一个概念,那就是“方法的重写”。重写又叫覆盖,英文名为“Override”。虽然”重写”、 ”覆盖”、“Override”这些名词都很容易记住,但很多人(包括我)并没有真正理解Java语言为什么要提供“重写”这种编程机制,也不知道什么时候该重写父类中的方法。今天,我打算花费5个小时,写两篇博客,彻底把方法重写和方法重载剖开来分析,我势必要弄懂这些散乱和零碎的知识点。

致读者

对于看到这篇博客的你们,其实不需要刻意的去记这些知识,可以收藏起来,有事没事翻开看看,这些其实看得多了,自然就烂熟于心了,如果你只是刻意的记忆了一遍,那其实你很快就会忘记,即使你当时看完可能觉得懂了,但事实上你很快就会忘了,过几个星期,你根本回忆不起来,感觉好像没看过这篇文章似的。所以说,赶紧先收藏,随时拿出来看,不然真的吃亏。

问题引入

假设有一个类叫做Father,并且我们假设因为某种原因,我们只能使用这个类,但没有办法修改这个类的源代码。Father类中提供了一个能够求正整数累加之和的方法叫做sum。(所谓“累加”就是从1一直加到某个数,比如1+2+3+...+100)代码如下

后来,我们又编写了一个类叫做Child,它继承了Father类。其他方面都没什么问题,但Father类所提供的这个用于求整数累加之和的方法sum()效率实在太低了,每做一次累加都要执行多次循环。求整数累加之和明明可以用更高效的方法实现,但出于某种原因,我们无法修改Father类的源代码,难道我们继承了Father类就只能被迫选择使用这个效率很低的sum()方法吗?

幸好,Java语言提供了“重写”这种编程机制。重写,顾名思义,就是在子类中把继承自父类的某个方法重新写一遍。这样就能在子类中弄出一个同名的、更适合自身或者是效率更高的方法。于是我们就可以在子类中重写了sum()方法,代码如下:

通过观察代码我们不难发现,重写之后的sum()方法摒弃了循环求和的算法,而采用了更高效的等差数列求和的方法完成累加的计算。这样明显提高了运算效率。当我们创建一个子类对象,并且调用该对象的sum()方法时,虚拟机将会调用重写之后的sum()方法,而不是父类中那个老的sum()方法。

但是,如果我们在代码在中,使用了父类的引用去指向子类对象的时候,还能不能调用到那个重写之后的sum()方法呢?看下面的代码:

从上面的代码中我们可以看到,创建了一个Child类对象,但是指向这个对象的对象的引用f却是一个Father类的引用。那么在这种情况下,当我们通过引用f调用sum()方法的时候,调用到的父类中的sum()方法,还是子类中重写过的sum()方法呢?执行main()方法,运行结果如下:

                                 

根据方法的运行结果,我们可以看出,即使我们使用父类的引用去指向子类的对象,只要引用实际所指向的对象是子类的对象,那么通过这个引用调用方法的时候,调用到的就是子类的方法,父类的中的那个方法仿佛被屏蔽了,因此方法的重写也叫“覆盖”。

其实,“重写”和“覆盖”这两个词是从两个不同的角度描述了这种编程机制。“重写”是从编码的角度来说的,它体现了子类“重新编写”了父类的某个方法,因此叫“重写”。而“覆盖”是从代码运行效果的角度来说的,它形象的体现出:当子类重写了父类的某个方法之后,当子类对象通过方法名称调用该方法,不会调用到父类中定义的那个方法,只能调用到子类中所定义的那个同名方法,父类中的那个方法如同被子类中重新定义的同名方法覆盖住不见踪影一样,因此叫“覆盖”。

通过以上这个小例子,我们能够体会到:Java语言中引入重写机制,为的就是让我们在编码的时不必受限于父类。子类可以继承父类的方法以减少编码量,但是如果认为父类的某个方法不适合自身,或者这个方法效率不高,子类完全可以重新编写一个更加适合自身或效率更高的同名方法去代替它。

虽然我已经理解了什么是方法的重写,但我其实还是不清楚在什么情况下要重写父类的方法,在此我总结出需要进行方法重写的三种常见情况。

重写的三种常见情况

一、父类要求子类重写

这种情况其实就是指父类无法定义出某个方法的实现过程,于是只能把这个方法定义成抽象方法,从而强制子类去重写这个抽象方法。这个过程虽然被称为“实现”,但它实际上就是对某个方法的重写。因为从本质上来讲,这个过程就是把父类的一个没有实现过程的空方法(即抽象方法)重新编写为一个有具体实现过程的方法。

二、父类中的方法不适合子类

子类如果继承了父类的某个方法,但发现这个方法并不适合自己,就需要重写这个方法。最典型的例子就是表示字符串的String类继承了Object类的equals()方法。但Object类中的equals()方法是用来比较两个对象是否为同一个对象,String类则希望自己的equals()方法能够比较两个字符串的“内容”是否相同,于是在String类当中就重写了equals()方法。有兴趣的小伙伴可以自己去查看一下这两个类当中的equals()方法源码。

三、父类中的方法效率较低或算法陈旧

第三种情况就是:由于各种历史问题的原因,导致原先父类中定义的方法存在效率偏低或算法陈旧,以及线程不安全等情况,并且我们还不能修改父类方法的源代码。在这种情况下,子类就可以用更先进的实现过程来重写父类中的方法。刚才我们看到的Father类和Child类的例子就属于这种情况。

另外,我们还必须要强调一个原则,那就是:子类在重写父类方法的时候,不能更改父类方法的原宗旨。比如说:父类Father中的sum()方法是用来求累加之和的,子类Child在重写父类的sum()方法的时候,就不能把sum()方法改成求阶乘的运算。这个原则适用于所有情况的方法重写,请务必牢记。

接下来我们再来说说子类在重写父类方法的时候,必须遵守的那些语法规则。子类重写父类的方法,需要遵守“三同不降不多抛”的七字规则。

重写的七字规则

所谓“三同”就是指子类重写的方法要与父类中原方法的名称、参数和返回值都相同。如果方法名称不相同,将被编译器视为子类新扩展出的方法。同理,如果方法的参数不同,则被编译器视为子类新增加了一个“重载”关系的方法。如果返回值不同,则被编译器视为违反重写规则。

语法规则“三同不降不多抛”中的“不降”是指子类重写父类方法时,不能降低方法的访问度。比如说,父类声明方法的访问度为“public”,子类就不能擅自将方法的访问度降为“protected”或者是更低的访问度,否则将无法通过语法检查。

接下来说说“不多抛”。所谓“不多抛”是子类重写父类方法时,不能用throws关键字声明抛出更多的异常。这里的“更多”并不是指数量上的多,而是指范围不能扩大。可以看看这幅图帮助理解:

从图中我们可以看出,虽然从数量上来讲,父类的test()方法声明抛出两个异常,子类重写的test()方法只声明抛出一个异常,但子类声明的是Exception,Exception代表了所有的异常,换句话说就是:Exception所能代表的异常的种类更多、范围更大。因此虽然从数量上子类的test()方法没有比父类的test()方法抛出更多异常,但范围却扩大了,这也是不允许的。

我们在实际开发过程中,有的时候会因为粗心导致子类并没有真正的重写父类的方法。比如说父类定义的方法名为”sum”,而子类中却把这个方法错误的写成了”snm”。程序员可能因为粗心没有发现这个错误,导致自己写了半天代码却没有实现“覆盖”的效果。为了避免这种错误,我们在重写某个方法的时候,可以在方法的上面加上@Override注解。一旦加上这个注解,编译器就知道这个方法是意图覆盖父类中的某个方法,于是就会检查父类中是否有同名方法,如果发现子类中的方法与父类中任何一个方法都不同名,那么就标出语法错误来提示程序员。同时,其他程序员看到@Override注解,也能立刻明白这个方法是重写了父类的某个方法。因此,我们最好在所有重写的方法前面都要加上@Override注解。

当子类重写了父类中的某个方法之后,如果从子类内部去调用这个方法的时候,调用到的一定是重写之后的那个方法。不理解的同学还是看下图

从图上我们可以看出,在子类的method()方法中去调用test()方法,调用到的是子类重写过的test()方法。但是,如果我们希望在子类内部调用父类中那个被覆盖了的test()方法该怎么办呢?这时候,我们必须在方法的前面加上super关键字,代码如下:

在test()方法的前面加上super关键字,可以从子类的内部调用到那个已经被覆盖了的父类的test()方法。

有读者会问:以上讲解的都是子类重写父类方法的知识点,那么父类是否真的如同“被宰割的羔羊”一般,任由子类重写它所定义的方法吗?如果我们定义一个类,能否不让子类去重写这个类中的方法呢?当然是可以的,我们只要在某个方法的前面加上一个final关键字,那么子类就无法重写这个方法啦!

参考文献:

如何理解Java中重写(覆盖、Override) - 知乎 (zhihu.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/349372.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据库学习】pg安装与运维

1,安装与配置 #安装 yum install https:....rpm1)安装目录 bin目录:二进制可执行文件目录,此目录下有postgres、psql等可执行程序;pg_ctl工具在此目录,可以通过pg_ctl --help查看具体使用。 conf目录&…

Journal of Intelligent Fuzzy Systems期刊的格式要求

摘要 摘要应该清晰、具有描述性,自说明,并且不超过200字。同时,它应该适合在文摘服务中发布。请在摘要中不要包含参考文献或公式。 关键词:关键词一,关键词二,关键词三,关键词四,关…

电商API接口接入|电商爬虫实践附代码案例

1.爬虫是什么 首先应该弄明白一件事,就是什么是爬虫,为什么要爬虫,百度了一下,是这样解释的:网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追…

银行数据仓库体系实践(6)--调度系统

调度系统是数据仓库的重要组成部分,也是每个银行或公司一个基础软件或服务,需要在全行或全公司层面进行规划,在全行层面统一调度工具和规范,由于数据类系统调度作业较多,交易类系统批量优先级高,为不互相影…

算法------(10)堆

例题:(1)AcWing 838. 堆排序 我们可以利用一个一维数组来模拟堆。由于堆本质上是一个完全二叉树,他的每个父节点的权值都小于左右子节点,而每个父节点编号为n时,左节点编号为2*n,右节点编号为2*…

10. UE5 RPG使用GameEffect创建血瓶修改角色属性

前面我们通过代码实现了UI显示角色的血量和蓝量,并实现了初始化和在数值变动时实时更新。为了测试方便,没有使用GameEffect去修改角色的属性,而是通过代码直接修改的数值。 对于GameEffect的基础,这里不再讲解,如果需要…

跨境电商的网络为什么要用云桥通SDWAN企业组网?

传统的WAN连接通常由交换机和路由器构成,然而,随着企业内部网络的扩张和变革,传统WAN的管理和配置变得复杂繁琐。云桥通SDWAN组网采用了较新的技术方式,通过中央控制器对局域网设备进行管理和配置,从而实现了更为灵活、…

Java工程师的你,真的不想了解一下《类文件结构》吗?

身为Java工程师的你,真的不想了解一下《类文件结构》吗? 文章目录 身为Java工程师的你,真的不想了解一下《类文件结构》吗?回顾一下字节码Class 文件结构总结魔数(Magic Number)Class 文件版本号&#xff0…

彩虹PLM系统 产品数据管理解决方案

彩虹PLM系统 产品数据管理解决方案 当企业面临以下问题时,可能需要考虑引入 彩虹PLM系统: 随着市场竞争的日益激烈,企业需要不断提高自身的竞争优势和生产效率。然而,许多企业在产品研发、生产和管理方面仍然面临着诸多挑战。 例…

应急响应-Windows-进程排查

进程(process)是计算机中的程序关于某数据集合上的一次运动活动,是系统进行资源分配和调度的基本单位,是操作系统结果的基础。在早期面向进程结构中,进程是线程的容器。无论是在Windows系统还是Linux系统中&#xff0c…

探索二手旧物回收小程序:环保与经济的完美结合

随着社会的进步和人们生活水平的提高,消费观念也在不断变化。然而,在追求时尚和品质的同时,我们也面临着资源浪费和环境污染的问题。为了解决这些问题,二手旧物回收小程序应运而生。 一、二手旧物回收小程序的背景和意义 随着消…

小程序 样式 WXSS

文章目录 样式 WXSS尺⼨单位样式导⼊选择器⼩程序中使⽤less 样式 WXSS WXSS( WeiXin Style Sheets )是⼀套样式语⾔,⽤于描述 WXML 的组件样式。 与 CSS 相⽐,WXSS 扩展的特性有: 响应式⻓度单位 rpx样式导⼊ 尺⼨单位 rpx (…

滴滴基于 Ray 的 XGBoost 大规模分布式训练实践

背景介绍 作为机器学习模型的核心代表,XGBoost 在滴滴众多策略算法业务场景中发挥着至关重要的作用。因此,保障并持续提升 XGBoost 模型的离线训练及在线推理稳定性一直是机器学习平台的重点工作。同时,面对多样化的业务场景定制需求和数据规…

Matlab图像增强学习笔记——imadjust函数的使用

1.引言 图像增强是数字图像处理领域中的一个重要主题,它涉及改进图像的对比度、亮度和色彩等方面,以使图像更适合于特定应用或更易于分析。Matlab 提供了丰富的图像处理工具,其中 imadjust 函数是一种强大的图像增强工具。本篇文章将深入学习…

年老返乡难,凭君传语报平安

惧于媒体谎言多,浏览社交媒体发布的国内外五花八门的时事新闻报道,踯躅良久,笔者放弃选择话题置评,只得履行本“人民体验官”义务,推广人民日报官方微博文化产品《你好,回家!》,敷衍…

【Java网络编程03】网络原理进阶

【Java网络编程03】网络原理进阶 1. UDP协议 1.1 基本介绍 我们首先再来回顾UDP协议的基本特点: 无连接的不可靠传输的面向数据报的全双工的 既然谈到数据报,我们就来看一下UDP数据报的格式: UDP数据报分为报头和载荷部分,其…

臻于至善,CodeArts Snap 二维绘图来一套不?

前言 我在体验 华为云的 CodeArts Snap 时,第一个例子就是绘制三角函数图像,功能注释写的也很简单。 业务场景中,有一类就是需要产出各种二维图形的,比如,折线图、散点图、柱状图等。 为了提前积累业务素材&#xf…

AG32VF407 AGRV2K 串口printf调试输出

视频讲解 [AG32VF407]国产MCUFPGA 串口printf调试输出及演示 原理图 测试代码 新建一个platformio工程,复制如下文件到测试工程目录下 E:\tech\AGM-AG32VF\sdk-release\AgRV_pio\platforms\AgRV\boards\agrv2k_407\board.asf E:\tech\AGM-AG32VF\sdk-release\AgRV_…

WordPress反垃圾评论插件Akismet有什么用?如何使用Akismet插件?

每次我们成功搭建好WordPress网站后,都可以在后台 >> 插件 >> 已安装的插件,在插件列表中可以看到有一个“Akismet反垃圾邮件:垃圾邮件保护”的插件(个人觉得是翻译错误,应该是反垃圾评论)。具…

C/C++ 跨文件共享全局变量

目录 效果 项目 代码 下载 为了实现跨文件共享全局变量,我们可以使用 extern 关键字。extern 关键字用于声明一个变量,该变量在其他地方已经定义。它告诉编译器这个变量在其他文件中已经定义了,不需要重新分配内存空间,只需要…