Java静态和动态绑定、重载
我正在练习一个测试,我遇到了这个关于重载以及静态和动态绑定的练习。询问以下代码的输出:
class Moe {
public void print(Moe p) {
System.out.println("Moe 1");
}
}
class Larry extends Moe {
public void print(Moe p) {
System.out.println("Larry 1");
}
public void print(Larry l) {
System.out.println("Larry 2");
}
}
class Curly extends Larry {
public void print(Moe p) {
System.out.println("Curly 1");
}
public void print(Larry l) {
System.out.println("Curly 2");
}
public void print(Curly b) {
System.out.println("Curly 3");
}
}
class Overloading {
public static void main (String [] args) {
Larry stooge1 = new Curly();
Moe stooge2 = new Larry();
Moe stooge3 = new Curly();
Curly stooge4 = new Curly();
Larry stooge5 = new Larry();
stooge1.print(new Moe());
stooge1.print(new Curly());
stooge1.print(new Larry());
stooge2.print(new Curly());
stooge3.print(new Curly());
stooge3.print(new Larry());
stooge5.print(new Curly());
}
}
我想我得到了第一个,但是其他的我完全迷路了。这是我如何解决第一个问题的:
在运行时stooge1
的类型是Curly
,因此我们调用Curly的print方法。因为我们将类型为Moe
的对象传递给print,所以参数类型为Moe
的对应print方法在Curly
中运行。这个方法的输出是Curly 1
,这是正确的答案
然而,当我将这种技巧应用于以下几行时,我最终得到了错误的答案。有人能解释一下这个概念在Java中到底是如何工作的吗
代码的正确输出为:
Curly 1
Curly 2
Curly 2
Larry 1
Curly 1
Curly 1
Larry 2
# 1 楼答案
对于#1、#2、#3
stooge1
被声明为Larry
,因此只能调用Larry
可用的方法传递
Moe
将调用print(Moe)
。因为实际的类是Curly
,所以它打印“Curly 1”传递一个
Larry
将调用print(Larry)
,因为这是一个更好的匹配print(Moe)
。这将打印“卷曲2”传递
Curly
也将调用print(Larry)
。请注意print(Curly)
对stooge1
是未知的,因此编译器无法选择它。因此,它还打印“Curly 2”现在试着找出剩下的
# 2 楼答案
这是一个非常令人困惑和可怕的例子,说明你永远不应该做的事情。所声明的变量类型对签名方法有什么影响。因此
Larry
没有接受Curly
的方法,因此编译器将参数视为Larry
。但是它被分派到Curly
的方法版本所以是的,永远不要这样做
# 3 楼答案
静态绑定发生在编译时,动态绑定发生在运行时
静态绑定负责选择应该执行的方法的签名(名称和参数类型)。它使用
编译器从调用方法的变量类型中选择签名,因此
Object o = "abc";
将不允许调用o.substring(1,2);
,因为编译器将无法在Object
类(调用substring
方法的o
变量类型)中找到substring(int, int)
签名动态绑定负责在编译时查找和调用静态绑定选择的方法的代码。它将尝试在变量持有的实际实例类型中查找方法代码。换句话说,如果你有
Animal a = new Cat(); a.makeSound();
,你可以期望得到结果"Mew"
,因为在运行时JVM将从Cat
类开始搜索和调用makeSound
的代码。如果该类中不提供实现,JVM将在祖先中搜索它,直到找到继承它的祖先我对您的示例中的类和变量进行了一些重命名,希望使其更具可读性:
(变量命名—>;类型为
X
的变量,其持有类型为Y
的实例的名称为xy
)所以,当我们执行
B
中找到可以处理类型A
的实例的最佳print
方法签名。在这种情况下,它将是print(A)
李>C
中搜索该方法的代码(因为这是由bc
变量持有的实例类型),这意味着我们将看到C.print(A)
李>类似地,在
bc.print(new C());
B
类中可用的C
参数找到最佳的print
方法,而C
的print(B)
(因为那里没有print(C)
,B是最接近的超类型)李>C
类中查找哪个方法(因为这是bc
持有的实例)李>因此,它将调用
C.print(B)
# 4 楼答案
下面是发生的事情:
其余三种情况可以通过应用与上述相同的逻辑来解决