![](/img/trans.png)
[英]Spring Boot - Conditionally load module during runtime or compile-time
[英]left and right objects are evaluated / resolved during runtime or compile-time?
参考书籍练习......
有以下代码..
Left left = createLeftInstance ();
Right right = createRightInstance ();
...并且考虑到上述两种方法都可以返回Left和Right的所有子类的实例,在Java中调用以下方法......
left.invoke (right);
怎么解决:
实际上,我认为技术上正确的答案是“以上都不是”。
在编译时,您需要知道left
变量( Left
)和right
变量( Right
)的声明类型。 这将确定Left::invoke
方法的哪个方法重载1最适用于Right
类型的参数。
在运行时, left
的实际类型将决定调用哪个实际方法。
所以完整的答案是:
E)基于编译时AND运行时类型的
left
和right
编译时类型。
但是,我怀疑教科书中这个问题的关键是帮助您区分非重载方法的编译时解析和运行时方法调度。 为此目的,A)“足够正确”。
1 - 为了进行确定,编译器需要将Right
及其超类型与Left
及其超类型声明的invoke
方法的不同方法重载进行比较。 如果存在多个重载,则编译器需要选择“最具体的适用”重载。
A)这里是正确的答案。
以下代码演示了这一点。
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());
}
}
这个例子打印
Invoking method A on B2 with argument A2
Done!!!
这意味着A)是正确的答案。
为什么这意味着?
嗯...因为:
1)从B2类的方法被调用(作为输出表示)和B2是的运行时类型left
(的编译时间类型left
是B)。
2)与参数A的方法被调用(注意,A是的编译时间类型right
),即使的运行时类型right
是A2。 编译时间类型的right
只是声明right
的类型,即A.运行时类型的right
是参数的实际类型,即A2(参见输出,它with argument A2
表示)。
Java有A ,它叫做单调度 :
right
与编译时类型left
提供的方法相匹配) left
的运行时类型上 - 因为方法不会消失, left
肯定有一个具有相同签名的方法,该方法在编译时被选中。 此行为计为“调度”,因为它仅取决于left
(在运行时),它是“单一”。 使用内置println(Object)
和println(char[])
超级简单演示:
char c[]={'a','b','c'};
System.out.println(c);
Object o=c;
System.out.println(o);
它导致类似的东西
abc [C@1540e19d
第一行显示println(char[])
连接字符数组,第二行显示完全相同的数组(可以添加一些检查,如println(o==c);
)在编译时结果中作为Object
传递在调用println(Object)
重载时,无论运行时类型如何。
B和C可能不存在。
当在运行时使用参数的实际运行时类型选择方法签名时, D称为多分派 ,并且在left
运行时类型上调用所选方法。 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
因为println
是使用参数的运行时类型手动选取的。 因此,如果有人真的需要它在Java中,它可以做,但它不会自动发生。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.