gpt4 book ai didi

java - Java-插入参数(参数)时输出已更改

转载 作者:行者123 更新时间:2023-12-01 11:39:53 26 4
gpt4 key购买 nike

对于以下代码,在将A2和B2类的参数“ A2 a”和“ B2 b”插入后,输出已更改。我想知道为什么?

A1级:

public class A2 
{
public void m1(A2 a)
{
System.out.println("A2");
}

}


B2类:

public class B2 extends A2 
{
public void m1(B2 b)
{
System.out.println("B2");
}

}


主类(运行程序):

public class D2 
{
public static void main(String[] args)
{
A2 x = new A2();
A2 y = new B2();
B2 z = new B2();

y.m1();
}

}

最佳答案

在插入参数之前,B2.m1()会覆盖A2.m1(),因此调用的方法仅取决于接收方的运行时类型。

插入参数后,两个m1方法具有不同的类型签名,并且B2.m1(B2 b)不再覆盖A2.m1(A2 a)。这样,调用的方法取决于接收方和所发送参数的编译时类型。

鉴于:

   A2 x = new A2();
A2 y = new B2();
B2 z = new B2();

y.m1(x); // calls A2.m1(A2 a)
y.m1(z); // calls A2.m1(A2 a)
z.m1(x); // calls A2.m1(A2 a)
z.m1(z); // calls B2.m1(B2 b)


在添加参数之前:

   y.m1();    // would have called B2.m1()


那是您看到的差异吗?

编辑:下面也添加了所有细节。

首先,您可以认为签名基本上是方法的名称与数字的组合
和形式参数的类型。您可能会看到它们以“ m1:(LA2;)V”或“ m1:(LB2;)V”的形式编写
(名为“ m1”的方法,该方法接受1个类类型为 A2的参数并返回Void)。但是在这里我只是
编写 m1(A2)m1(B2)使其更容易。

确定最终调用什么方法基本上有两个步骤。编译时步骤
和运行时步骤。编译时步骤确定要调用的方法的签名。的
运行时步骤通过找到具有该签名的类来选择要调用的实际方法
对象的创建时间。如果在那里找不到,它将向上移动类直到
找到具有该签名的方法(必须在某处,否则就不会编译)。

为了找到签名,使用了编译时类型(也称为“静态类型”)(
用于声明变量)。这适用于接收器和参数。

因此,让我们看一下每种情况下选择的签名:

y.m1(x)


y被声明为 A2,因此唯一可能的签名是 m1(A2)

y.m1(z)


同样, yA2,因此唯一的可能性是 m1(A2)zB2的事实很好,因为
您总是可以在需要 B2的地方传递 A2。 (在此过程中,
在运行时 y将被创建,因为 B2无关紧要!)

z.m1(x)


zB2。在 B2中有两种可能性。 m1(B2)和继承的 m1(A2)。自 x
A2,则不可能是第一个(您不能在需要 A2的地方传递 B2),所以一旦
再次,我们留下了 m1(A2)

z.m1(z)


zB2。在 B2中有两种可能性。 m1(B2)和继承的 m1(A2)。自 z
B2,两者都是可能的。 Java在这里有一个选择规则,那就是选择
最特定(最派生)的参数类型,因此选择了 m1(B2)

在上述所有情况下,在运行时都无需再决定,因为在每种情况下都有
具有给定签名的仅一种方法。以 y.m1(z)为例。在运行时,Java将寻找
在编译时步骤中确定的具有签名 m1(A2)的方法。

首先,由于 B2被创建为 y对象,因此它将在类 B2中查找。但是这里没有办法
具有该签名(只有 m1(B2))。一旦 zB2对象,
在编译时确定签名,只有具有该签名的方法才会被调用
在运行时。因此,Java进入了层次结构,并在类中找到了具有正确签名的方法
A2,因此结果就是您所看到的。 (请注意,这是概念性和实际性
生成的代码将其转换为正确的方法要比这聪明一点。)

现在,在添加参数之前,两个m1方法都被命名为“ m1”并且没有参数,因此它们具有
相同的签名 m1()。所以看着

y.m1()


编译时步骤: yA2,因此唯一被选择的可能性是m1()。

然后在运行时,由于 y被创建为 B2,因此Java从类 B2开始查找方法
那个签名。找到一个! m1()中的 B2方法具有与 m1()相同的签名
A2中的方法。换句话说,与上述情况不同, B2 .m1确实覆盖了 A2.m1。所以java是
如您在添加参数之前所见,很高兴在 m1()中调用 B2的版本。

这就是故事。我知道这很令人困惑,但这是理解Java(和其他对象)的关键
面向语言)和您正在深入研究的伟大知识。

阅读有关覆盖与重载,多态,动态调度和虚拟的所有内容
方法表。

我认为最重要的一点是:

-仅当您重写方法时,您才能基于运行时进行动态调度
接收器类型

-如果签名,则派生类中的方法仅覆盖基类中的方法
是一样的

关于java - Java-插入参数(参数)时输出已更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29617666/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com