[英]left and right objects are evaluated / resolved during runtime or compile-time?
Referring to a book exercise... 参考书籍练习......
Having the following code.. 有以下代码..
Left left = createLeftInstance ();
Right right = createRightInstance ();
...and keeping in consideration that both the above mentioned methods can return instance of all the sub-classes of Left and Right, in Java the call of the following method... ...并且考虑到上述两种方法都可以返回Left和Right的所有子类的实例,在Java中调用以下方法......
left.invoke (right);
how is resolved: 怎么解决:
Actually, I think that the technically correct answer is "none of the above". 实际上,我认为技术上正确的答案是“以上都不是”。
At compile time, you need to know the declared types of the left
variable ( Left
) and the right
variable ( Right
). 在编译时,您需要知道
left
变量( Left
)和right
变量( Right
)的声明类型。 This will determine which method overload 1 of the Left::invoke
method is most applicable to a parameter of type Right
. 这将确定
Left::invoke
方法的哪个方法重载1最适用于Right
类型的参数。
At runtime, the actual type of left
will determine which actual method gets called. 在运行时,
left
的实际类型将决定调用哪个实际方法。
So the complete answer is: 所以完整的答案是:
E) based on compile-time AND runtime types of
left
and on the compile-time type ofright
.E)基于编译时AND运行时类型的
left
和right
编译时类型。
However, I suspect that the point of this question in the textbook is to help you distinguish between compile-time resolution of non-overloaded methods and runtime method dispatching. 但是,我怀疑教科书中这个问题的关键是帮助您区分非重载方法的编译时解析和运行时方法调度。 For that purpose, A) is "correct enough".
为此目的,A)“足够正确”。
1 - To make the determination, the compiler needs to compare Right
and its supertypes with the different method overloads of the invoke
method declared by Left
and its supertypes. 1 - 为了进行确定,编译器需要将
Right
及其超类型与Left
及其超类型声明的invoke
方法的不同方法重载进行比较。 If there are multiple overloads, the compiler needs to choose the "most specific applicable" overload. 如果存在多个重载,则编译器需要选择“最具体的适用”重载。
A) is the correct answer here. A)这里是正确的答案。
The following code demonstrates that. 以下代码演示了这一点。
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());
}
}
This example prints 这个例子打印
Invoking method A on B2 with argument A2
Done!!!
which means A) is the correct answer. 这意味着A)是正确的答案。
Why does it mean that? 为什么这意味着?
Well... because: 嗯...因为:
1) a method from the B2 class is invoked (as the output says) and B2 is the runtime type of left
(the compile time type of left
is B). 1)从B2类的方法被调用(作为输出表示)和B2是的运行时类型
left
(的编译时间类型left
是B)。
2) a method with parameter A is invoked (note that A is the compile-time type of right
), even though the runtime type of right
is A2. 2)与参数A的方法被调用(注意,A是的编译时间类型
right
),即使的运行时类型right
是A2。 Compile time type of right
is just the type with which right
is declared ie A. Runtime type of right
is the actual type of the argument ie A2 (see the output, it says with argument A2
there). 编译时间类型的
right
只是声明right
的类型,即A.运行时类型的right
是参数的实际类型,即A2(参见输出,它with argument A2
表示)。
Java has A , it is called single dispatch : Java有A ,它叫做单调度 :
right
to the methods offered by the compile-time type of left
) right
与编译时类型left
提供的方法相匹配) left
- as methods do not disappear, left
certainly has a method with the same signature which was picked at compile-time. left
的运行时类型上 - 因为方法不会消失, left
肯定有一个具有相同签名的方法,该方法在编译时被选中。 This act counts as "dispatch", and as it only depends on left
(in runtime), it is "single". left
(在运行时),它是“单一”。 Super simple demo using built-in println(Object)
and println(char[])
: 使用内置
println(Object)
和println(char[])
超级简单演示:
char c[]={'a','b','c'};
System.out.println(c);
Object o=c;
System.out.println(o);
It results in something like 它导致类似的东西
abc [C@1540e19d
The first line shows that println(char[])
concatenates the array of characters, the second line shows that the exact same array (one can add some check like println(o==c);
) passed as Object
in compile-time results in invoking the println(Object)
overload, regardless of the runtime type. 第一行显示
println(char[])
连接字符数组,第二行显示完全相同的数组(可以添加一些检查,如println(o==c);
)在编译时结果中作为Object
传递在调用println(Object)
重载时,无论运行时类型如何。
B and C probably do not exist. B和C可能不存在。
D is called multiple dispatch , when the method signature is also selected in runtime using the actual runtime type of the arguments, and the selected method is invoked on the runtime type of left
. 当在运行时使用参数的实际运行时类型选择方法签名时, D称为多分派 ,并且在
left
运行时类型上调用所选方法。 Java does not support that by default, it can be implemented using reflection, here is a single-argument example: 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
as println
is picked manually, using the runtime type of the argument. 因为
println
是使用参数的运行时类型手动选取的。 So it is possible to do if someone really needs it in Java, but it does not happen automatically. 因此,如果有人真的需要它在Java中,它可以做,但它不会自动发生。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.