Java静态和动态绑定,重载 [英] Java Static and Dynamic Binding, Overloading
问题描述
我正在为测试做练习,我遇到了有关重载以及静态和动态绑定的练习.询问以下代码的输出:
I am practicing for a test and I came across this exercise about overloading and static and dynamic binding. The output of the following code is asked:
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());
}
}
我认为我得到了第一个,但在其他方面我完全迷失了.这就是我解决第一个问题的方法:
I think I get the first one but on the others I am completely lost. This is how I solved the first one:
在运行时stooge1
的类型为Curly
,因此我们将调用Curly的打印方法.因为我们传递了类型为Moe
的对象进行打印,所以参数类型为Moe
的相应打印方法在Curly
中运行.此方法的输出是正确的答案Curly 1
.
at runtime the type of stooge1
is Curly
, so we're calling the print method of Curly. Because we pass an object of type Moe
to print, the corresponding print method with argument type Moe
is run in Curly
. The output of this method is Curly 1
, the correct answer.
但是,当我将这种技术应用于以下几行时,我得到的答案是错误的.有人可以解释一下这个概念在Java中是如何工作的吗?
However, when I apply this technique to the following lines I end up with the wrong answers. Can someone explain me how exactly this concept works in Java?
代码的正确输出是:
Curly 1
Curly 2
Curly 2
Larry 1
Curly 1
Curly 1
Larry 2
推荐答案
静态绑定在编译时发生,动态绑定在运行时发生.
Static binding happens at compilation time and dynamic binding at runtime.
-
静态绑定负责选择应执行的方法的签名(名称和参数类型).它使用
Static binding is responsible for selecting signature (name and argument types) of method which should be executed. It uses
-
方法的
- 名称
- 具有参数的变量类型(编译器不假定运行时实际的对象变量将保留,他选择了能够处理所有可能情况的签名).
- 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
方法的o
变量的类型)中找到substring(int, int)
签名.
Compiler selects signature from variable type on which method is invoked, so Object o = "abc";
will not allow you to invoke o.substring(1,2);
because compiler will not be able to find substring(int, int)
signature in Object
class (which is type of o
variable on which substring
method was invoked).
动态绑定负责查找和调用在编译时通过静态绑定选择的方法的代码 .它将尝试查找变量持有的实际实例类型的方法的代码.换句话说,如果您具有Animal a = new Cat(); a.makeSound();
,则可以期望得到结果"Mew"
,因为在运行时JVM将从Cat
类开始搜索并调用makeSound
的代码.如果该类中未提供实现,则JVM将在祖先中搜索它,直到找到继承它的一个.
Dynamic binding is responsible for finding and invoking code of method selected by static binding at compilation time. It will try to find code of method in type of actual instance held by variable. In other words if you have Animal a = new Cat(); a.makeSound();
you can expect to get as result "Mew"
because at runtime JVM will search and invoke code of makeSound
starting from Cat
class. If implementation will not be provided in that class JVM will search for it in ancestor(s) until it finds one from which it was inherited.
在您的示例中,我对类和变量进行了重命名,以期使其更具可读性:
I renamed classes and variables in your example a little to hopefully make it more readable:
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
).
(variable naming -> variable of type X
holding instance of type Y
is named xy
).
所以,当我们执行
bc.print(new A());
- 静态绑定将尝试找到最佳的
print
方法签名在类B
中可用,该签名可以处理类型为A
的实例.在这种情况下,它将为print(A)
. - 之后,动态绑定将在类
C
中搜索此方法的 code (因为这是bc
变量持有的实例的类型),这意味着我们将看到C.print(A)
./li>- static binding will try to find best
print
method signature available in classB
which can handle instance of typeA
. In this case it will beprint(A)
. - after that dynamic binding will search for code of this method in class
C
(since this is type of instance held bybc
variable) which means we will seeC.print(A)
. - 静态绑定将尝试为
B
类中可用的C
参数找到最佳的print
方法,对于C
为print(B)
(因为那里没有print(C)
并且B是最接近的超类型) . - 因此,现在动态绑定知道要在
C
类中查找哪种方法(因为这是bc
所拥有的实例). - static binding will try to find best
print
method forC
argument available inB
class, which forC
isprint(B)
(since there is noprint(C)
there and B is closest supertype). - So now dynamic binding knows which method to look for in
C
class (since this is instance whichbc
holds).
对于
bc.print(new C());
因此它将调用
C.print(B)
.这篇关于Java静态和动态绑定,重载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- static binding will try to find best