3 回答

TA贡献1815条经验 获得超6个赞
实际上,我认为技术上正确的答案是“以上都不是”。
在编译时,你需要知道
left
变量(Left
)和right
变量(Right
)的声明类型。这将决定该方法的哪个方法重载1Left::invoke
最适用于 type 的参数Right
。在运行时, 的实际类型
left
将决定调用哪个实际方法。
所以完整的答案是:
E) 基于 的编译时和运行时类型
left
以及 的编译时类型right
。
但是,我怀疑教科书上这个问题的重点是帮助你区分非重载方法的编译时解析和运行时方法调度。为此,A) 是“足够正确”的。
1 - 为了做出决定,编译器需要将其超类型与声明Right
的方法及其超类型的不同方法重载进行比较。如果有多个重载,编译器需要选择“最具体适用”的重载。invoke
Left

TA贡献1744条经验 获得超4个赞
A) 是这里的正确答案。
下面的代码演示了这一点。
public class Main001 {
public static void main(String[] args) {
A right = createRightInstance();
B left = createLeftInstance();
left.invoke(right);
System.out.println("Done!!!");
}
public static B createLeftInstance() {
return new B2();
}
public static A createRightInstance() {
return new A2();
}
}
class A{
}
class A1 extends A{
}
class A2 extends A1{
}
class B{
public void invoke(A x) {
System.out.println("Invoking method A on B with argument " + x.getClass().getName());
}
public void invoke(A1 x) {
System.out.println("Invoking method A1 on B with argument " + x.getClass().getName());
}
public void invoke(A2 x) {
System.out.println("Invoking method A2 on B with argument " + x.getClass().getName());
}
}
class B1 extends B{
public void invoke(A x) {
System.out.println("Invoking method A on B1 with argument " + x.getClass().getName());
}
public void invoke(A1 x) {
System.out.println("Invoking method A1 on B1 with argument " + x.getClass().getName());
}
public void invoke(A2 x) {
System.out.println("Invoking method A2 on B1 with argument " + x.getClass().getName());
}
}
class B2 extends B1{
public void invoke(A x) {
System.out.println("Invoking method A on B2 with argument " + x.getClass().getName());
}
public void invoke(A1 x) {
System.out.println("Invoking method A1 on B2 with argument " + x.getClass().getName());
}
public void invoke(A2 x) {
System.out.println("Invoking method A2 on B2 with argument " + x.getClass().getName());
}
}
这个例子打印
Invoking method A on B2 with argument A2
Done!!!
这意味着 A) 是正确答案。
为什么是这个意思?
嗯......因为:
1)调用了 B2 类的方法(如输出所示)并且 B2 是运行时类型left(编译时类型left是 B)。
2) 调用了一个带参数 A 的方法(注意 A 是 的编译时类型right),即使 的运行时类型right是 A2。编译时类型 ofright只是right声明的类型,即 A。运行时类型 ofright是参数的实际类型,即 A2(请参阅输出,它with argument A2在那里说明)。

TA贡献2065条经验 获得超14个赞
Java 有A,它被称为single dispatch:
方法重载由编译器在编译时选择(将 的编译时类型与 的编译时类型
right
提供的方法相匹配left
)方法调用发生在运行时类型上
left
——因为方法不会消失,left
当然有一个方法具有在编译时选择的相同签名。此行为算作“调度”,并且因为它仅取决于left
(在运行时),所以它是“单一的”。
使用内置println(Object)
and的超级简单演示println(char[])
:
char c[]={'a','b','c'};
System.out.println(c);
Object o=c;
System.out.println(o);
它会产生类似的结果
abc
[C@1540e19d
第一行显示连接字符数组,第二行显示在编译时传递println(char[])的完全相同的数组(可以添加一些检查,如)导致调用重载,而不管运行时类型如何。println(o==c);Objectprintln(Object)
B和C可能不存在。
D称为多重分派,当方法签名也在运行时使用参数的实际运行时类型选择时,并且所选方法在 的运行时类型上被调用left。java默认是不支持的,可以用反射来实现,下面是一个单参数的例子:
public static void trickyprintln(Object o) throws Exception {
System.out.getClass().getMethod("println",o.getClass()).invoke(System.out,o);
}
public static void main (String[] args) throws Exception {
char c[]={'a','b','c'};
trickyprintln(c);
Object o=c;
trickyprintln(o);
}
这一个导致
abc
abc
asprintln是手动选择的,使用参数的运行时类型。所以如果有人真的需要它,在 Java 中是可以做到的,但它不会自动发生。
添加回答
举报