Java继承与多态性

Java继承与多态性,第1张

Java继承与多态性

对于问题的第一部分,我认为维基百科提供了一个很好的定义:

在面向对象的程序设计中,子类型多态或包含多态是类型理论中的一个概念,其中名称可以表示许多不同类的实例,只要它们与某个公共超类相关即可。包含多态性通常通过子类型化来支持,即,不同类型的对象可以完全替代另一种类型(其基本类型)的对象,因此可以通过公共接口进行处理。或者,可以通过类型强制(也称为类型转换)来实现包含多态性。

面向对象编程中的另一种称为多态性的 Wikipedia术语似乎很好地回答了您的问题。本文中的第二篇参考文章“
了解类型,数据抽象和多态性”也详细介绍了此问题。

Java中的这种子类型化功能是通过继承类和接口来实现的。尽管从继承的角度来看,Java的子类型功能可能并不总是很明显。以与泛型的协方差和逆方差为例。而且,数组在序列层次结构中的任何地方都不明显,但它们是可序列化和可克隆的。也可以说,通过原始扩展转换,Java中的数字类型也是多态的。并且运算符的行为取决于其 *** 作数。

无论如何,继承在某些这种多态性的实现中起着重要作用。

重载与覆盖

问题的第二部分似乎是关于选择给定方法的实现。显然,如果一个类重写了一个方法,并且您创建了该类的实例,则即使要通过父类的引用访问该对象,也要调用该方法的重写版本。

正如您所指出的那样, 正确 选择方法的 实现
是在运行时完成的,现在,要调用的方法的签名是在编译时确定的。由于重载是关于具有相同名称和不同签名的不同方法的,所以这就是为什么重写方法选择发生在编译时的原因。

编译时的覆盖方法选择

第15.12节“
方法调用表达式
”中的Java语言规范(JLS)详细解释了编译器遵循的过程,以选择正确的方法进行调用。

在那里,您会注意到这是一个 编译时 任务。JLS在15.12.2小节中说:

此步骤使用 方法名称参数表达式的类型
来定位可访问和适用的方法。可能有不止一种这样的方法,在这种情况下,选择了最具体的方法。

要验证其编译时性质,可以执行以下测试。

声明一个这样的类并进行编译。

public class ChooseMethod {   public void doSomething(Number n){    System.out.println("Number");   }}

声明第二个类,该类调用第一个类的方法并进行编译。

public class MethodChooser {   public static void main(String[] args) {    ChooseMethod m = new ChooseMethod();    m.doSomething(10);   }}

如果您调用main,输出将显示

Number

现在,向该类中添加第二个更具体的 重载 方法

ChooseMethod
,然后重新编译它(但不要重新编译另一个类)。

public void doSomething(Integer i) { System.out.println("Integer");}

如果再次运行main,则输出仍为

Number

基本上是因为它是在编译时决定的。如果您重新编译

MethodChooser
该类(带有主类的类),然后再次运行该程序,则输出将为
Integer

因此,如果要强制选择重载方法之一,则参数的类型必须在编译时且不仅在运行时与参数的类型相对应。

在运行时覆盖方法选择

同样,方法的签名是在编译时确定的,而实际的实现是在运行时确定的。

声明一个这样的类并进行编译。

public class ChooseMethodA {   public void doSomething(Number n){    System.out.println("Number A");   }}

然后声明第二个扩展类并进行编译:

public class ChooseMethodB extends ChooseMethodA {  }

在MethodChooser类中,您可以执行以下 *** 作:

public class MethodChooser {    public static void main(String[] args) {        ChooseMethodA m = new ChooseMethodB();        m.doSomething(10);    }}

如果您运行它,则会得到输出

NumberA
,这很好,因为该方法尚未被覆盖
ChooseMethodB
,因此调用的实现是的实现
ChooseMethodA

现在,在中添加重写的方法

MethodChooserB

public void doSomething(Number n){    System.out.println("Number B");}

并重新编译该代码,然后再次运行main方法。

现在,您得到了输出

Number B

这样,实现是在运行时选择的,不需要重新编译

MethodChooser
该类。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5429333.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-11
下一篇 2022-12-11

发表评论

登录后才能评论

评论列表(0条)

保存