我正在为测试做练习,并且遇到了有关重载以及静态和动态绑定的练习。询问以下代码的输出:
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
类型的对象进行打印,因此在Moe
中运行了参数类型为Curly
的相应打印方法。此方法的输出是正确的答案Curly 1
。但是,当我将这种技术应用于以下几行时,我得到的答案是错误的。有人可以解释一下这个概念在Java中的工作原理吗?
该代码的正确输出是:
Curly 1
Curly 2
Curly 2
Larry 1
Curly 1
Curly 1
Larry 2
最佳答案
静态绑定在编译时发生,动态绑定在运行时发生。
静态绑定负责选择应执行的方法的签名(名称和参数类型)。它用
方法名称
带有参数的变量的类型(编译器不假设运行时实际的对象变量将保留,他选择可以处理所有可能情况的签名)。
编译器从调用方法的变量类型中选择签名,因此Object o = "abc";
不允许您调用o.substring(1,2);
,因为编译器将无法在substring(int, int)
类(其为Object
类型)中找到o
签名。调用substring
方法的变量)。
动态绑定负责在编译时查找和调用通过静态绑定选择的方法的代码。它将尝试查找变量持有的实际实例类型的方法代码。换句话说,如果您具有Animal a = new Cat(); a.makeSound();
,则可以期望得到"Mew"
作为结果,因为在运行时JVM将从makeSound
类开始搜索并调用Cat
的代码。如果在该类中未提供实现,则JVM将在祖先中搜索它,直到找到从其继承的继承。
我在示例中对类和变量进行了重命名,以期使其更具可读性:
class A {
public void print(A a) {
System.out.println("A.print(A)");
}
}
class B extends A {
public void print(A a) {
System.out.println("B.print(A)");
}
public void print(B b) {
System.out.println("B.print(B)");
}
}
class C extends B {
public void print(A a) {
System.out.println("C.print(A)");
}
public void print(B b) {
System.out.println("C.print(B)");
}
public void print(C c) {
System.out.println("C.print(C)");
}
}
class OverloadingDemo {
public static void main (String [] args) {
A ab = new B();
A ac = new C();
B bb = new B();
B bc = new C();
bc.print(new A());
bc.print(new C());
bc.print(new B());
ab.print(new C());
ac.print(new C());
ac.print(new B());
bb.print(new C());
}
}
(保存类型为
X
的实例的类型为Y
的变量命名->变量名为xy
)。所以,当我们执行
bc.print(new A());
静态绑定将尝试在类
print
中找到最佳的B
方法签名,该类可以处理A
类型的实例。在这种情况下,它将为print(A)
。之后,动态绑定将在类
C
中搜索此方法的代码(因为这是bc
变量持有的实例类型),这意味着我们将看到C.print(A)
。对于
bc.print(new C());
同样静态绑定将尝试为
print
类中可用的C
参数找到最佳的B
方法,对于C
是print(B)
(因为那里没有print(C)
并且B是最接近的超类型)。因此,现在动态绑定知道要在
C
类中查找哪种方法(因为这是bc
拥有的实例)。因此它将调用
C.print(B)
。关于java - Java静态和动态绑定(bind),重载,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34866199/