我正在练习一个测试,我遇到了这个关于重载、静态和动态绑定的练习。将询问以下代码的输出:
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的打印方法。因为我们传递一个Moe类型的对象来打印,相应的带有参数类型Moe的打印方法在Curly中运行。这个方法的输出是Curly 1,正确的答案。
然而,当我将这一技术应用于以下几行时,我最终得到了错误的答案。有人能解释一下这个概念在Java中到底是如何工作的吗?
代码的正确输出是:
Curly 1
Curly 2
Curly 2
Larry 1
Curly 1
Curly 1
Larry 2发布于 2016-01-19 00:13:53
静态绑定发生在编译时,动态绑定发生在运行时。
- _name_ of method
- type of variables holding arguments (compiler doesn't assume what actual object variable will hold at runtime, he picks signature which will be able to handle all of possible cases).编译器从调用的方法的变量类型中选择签名,因此Object o = "abc";将不允许您调用o.substring(1,2);,因为编译器将无法在Object类中找到substring(int, int)签名(这是调用substring方法的o变量的类型)。
Animal a = new Cat(); a.makeSound();,您可以期望得到结果"Mew",因为在运行时,JVM将从Cat类开始搜索和调用makeSound代码。如果在该类中不提供实现,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());B中可用的最佳print方法签名,它可以处理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)。
发布于 2016-01-18 23:59:02
下面是正在发生的事情:
stooge1.print(new Moe()); // All three have overload for Moe,
// so the overload from the dynamic type of stooge1 gets called
stooge1.print(new Curly()); // Compiler thinks stooge1 is Larry,
// so it does not know that it has an overload for Curly.
// It uses the overload for Larry instead, because Curly is a Larry
stooge1.print(new Larry()); // Same logic as above applies.
stooge2.print(new Curly()); // Compiler thinks stooge2 is Moe, so its only overload
// is for Moe. Since the dynamic type is Larry, first overload is invoked其余三个案例可以通过应用上述相同的逻辑来解决。
发布于 2016-01-18 23:59:28
对于#1,#2,#3,stooge1被声明为Larry,因此只能调用Larry可用的方法。
传递一个Moe将调用print(Moe)。因为实际的类是Curly,所以它会打印"Curly 1“。
传递一个Larry将调用print(Larry),因为这是与print(Moe)更好的匹配。这将打印“卷2”。
传递一个Curly也会调用print(Larry)。注意,print(Curly)对stooge1来说是未知的,所以编译器不能选择它。因此,它也打印“卷2”。
现在试着找出剩下的。
https://stackoverflow.com/questions/34866199
复制相似问题