Java中的继承

OOP的特性中,第2条即为“继承”,很多人都对“继承”这个概念不甚明了,甚至导致了对多态的理解也产生偏差。很遗憾,导致这个问题的原因,还得归结于“继承”一词的翻译者。现在父类子类的继承关系已经深入人心,我写这篇文章的目的,则是要打破这种认知,消除由于文化差异所带来的理解困难问题。

 

C++和JAVA,两门语法相似的语言,在继承上,JAVA明显做得要比C++漂亮的多。可以看到,软件或者说是程序,毕竟是数学的衍生物,早期语言还是相当的偏重于符号语言而不是自然语言。当然,计算机只认二进制,那么在编译技术不完善的时代,使用符号,能有效的降低编译程序解析源文件的难度,譬如C++中使用“:”冒号表示继承关系,并且允许多重继承。因为仅仅是符号,那么编译器认识,程序员认识,学习者便犯迷糊。我不知道老外怎么去念class A : B,C这样的类申明,但翻译过来后,忽然变成了继承。在我看来,简直匪夷所思!

 

相比C++而言,JAVA的语法元素则显得优雅得多,继承关系(虽然我不喜欢这么称呼,但暂且如此吧)并未沿袭C++的传统,而是使用了一个关键字extends,估计是惯性的原因,现在学术界依然将其称之为“继承”,其实不难看明白,这个词是extend+s得来,词尾s不必多言,extend是关键,此处最恰当的释义为:“扩展”!

 

那么何为扩展?为什么需要扩展?扩展的是什么?

 

软件工程里面,有个很重要的事情,就是“代码复用”,也即“功能复用”,将需要重复使用的代码抽取出来,封装成函数,便是最简单的复用。此处还没有继承的概念,当OOP的思想出来后,出现了“类”——数据与行为的封装体。在类里面,数据被称之为属性(Attribute);而行为则被称之为函数(Funcation)或者方法(Method)。复用也就是复用这些个东西。什么情况下需要复用呢?当我们的代码有一部分功能已经完成,而我们对其功能感觉还不足以满足我们的需求,那么便要对其改造。当然,我们不能直接改已经完成的代码,只能退而求其次,将他的代码复制过来,然后把不满意的地方进行修改!这样短暂的满足了要求,但是问题又来了,原来的类升级了,部分功能更新了。我拿来一瞧,倘若改的是我们拿来之后改过的部分,那倒没什么问题,反证我们还是要改的。但如果改的是其他我们需要的功能,那么,我们必须再次拿出代码来复制一遍。这样的做法,谈不上复用。那么如何才能复用呢?做扩展,扩展什么,扩展一个类。类里面有什么,我们就可以扩展什么。属性、方法都可以!

 

首先扩展过后的类跟原来的类不是一个类,他们之间的关系很简单,新的类知道自己扩展的是谁,而反过来不行。例如A extends B,B是不知道被A扩展了的,只有通过A类去反推才能得知。A可以看做是B的另外一个版本。B不具备或者不满足的功能,在A里面重新做一下。这里有一个问题需要讲一下,类里面包含了对象的信息,而对象在内存里面,仅仅包含了数据,而没有方法,所有的方法都在类里面,当我们对某个对象的引用调用其方法时,等于将内存中,该对象的数据交给其方法去处理,那么此时就有个方法定位的问题。和明显,调用方法时就已经指明了这个方法的签名,那么从该对象的类开始搜寻,如果搜到该方法,则调用之,若搜索不到,则向上搜寻其超类,以此类推,直到搜到为止。如果自身存在和超类中一致的方法签名,根据自身优先原则,自身的方法将被调用,那么超类中的方法很自然就被遮盖了。注意此处的用词,为遮盖而不是替换,超类中的方法依然存在,只不过不会被调用而已。这个现象即被称之为方法覆盖,又称之为重写(Override)。想要调用,在方法内使用super关键字即可!

 

当我们的类不希望被继承(扩展),也即,设定某个类为最终版本,不允许有某个类对其进行扩展,那么该类应当被修饰为final,当你尝试去扩展一个final类时,会发生编译错误。而有些时候,我们并不完全限定死我们的类不被扩展,而仅仅是限定某些方法不被重写(因为子类是可以冒充超类的),那么我们就需要将对应的方法修饰为final,也即,此方法为最终版本,不允许修改!重写一个final方法会引发编译错误。

 

那么此时有个额外的问题,子类能够重载(Overload)超类的final方法?

 

答案是可以!

 

无论是重载自身还是超类的方法,重载的方法之间,除了方法名一致外,还有其他联系么?很明显,方法签名最重要的部分是方法名和参数类型列表!而重载即为同名不同参,也即是说,重载的方法之间,除了方法名很凑巧的一致外,本质上根本就完全是两个不同的方法,毫无关系而言。

 

但重写不行,因为方法签名一致或者说是兼容吧,那么如何兼容法呢?

一个方法的申明,有以下元素组成:修饰符,返回值类型,方法名,参数列表,异常类型集合

子类跟超类某方法的签名完全一致当然是最好,这个绝对没问题。

那么是不是必须一致呢,必须一致的只有方法名和参数列表而已,其他的因情况而异

异常集合,当然跟参数列表不一样,是无序的,你可以写多个。但是有一个原则,你所有的异常范围不能超越超类里面该方法所申明的异常范围。否则的话,就是挂羊头卖狗肉,编译不会通过。

修饰符也一样,访问性不能更狭隘,可以平级,但是绝对不能将public的方法写成private,理由同上!

而返回值有讲究,其原理基本也同上,不能更宽泛而已,但是这里有一个问题,JDK1.4到1.5有一个语法变更即是有关与此,1.4以前返回值是必须一致的,而到了1.5版本,返回值类型可以是超类中方法返回值类型的子类。

评论 2 您还未登录,请先 登录 后发表或查看评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页

打赏作者

焙焙龙

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值