左右对象在运行时或编译时评估/解析?

参考书本练习...

有以下代码..

Left left = createLeftInstance ();
Right right = createRightInstance ();

...并考虑到上述两种方法都可以返回 Left 和 Right 的所有子类的实例,在 Java 中调用以下方法...

left.invoke (right);

怎么解决的:

  • A)基于左侧的运行时类型和右侧的编译时

  • B) 基于左边的编译时类型和右边的运行时类型

  • C) 基于左边的编译时类型和右边的编译时类型

  • D)基于左边的运行时类型和右边的运行时

守候你守候我
浏览 118回答 3
3回答

红糖糍粑

实际上,我认为技术上正确的答案是“以上都不是”。在编译时,你需要知道left变量(Left)和right变量(Right)的声明类型。这将决定该方法的哪个方法重载1Left::invoke最适用于 type 的参数Right。在运行时, 的实际类型left将决定调用哪个实际方法。所以完整的答案是:E) 基于 的编译时和运行时类型left以及 的编译时类型right。但是,我怀疑教科书上这个问题的重点是帮助你区分非重载方法的编译时解析和运行时方法调度。为此,A) 是“足够正确”的。1 - 为了做出决定,编译器需要将其超类型与声明Right的方法及其超类型的不同方法重载进行比较。如果有多个重载,编译器需要选择“最具体适用”的重载。invokeLeft

慕无忌1623718

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 A2Done!!!这意味着 A) 是正确答案。为什么是这个意思?嗯......因为:1)调用了 B2 类的方法(如输出所示)并且 B2 是运行时类型left(编译时类型left是 B)。2) 调用了一个带参数 A 的方法(注意 A 是 的编译时类型right),即使 的运行时类型right是 A2。编译时类型 ofright只是right声明的类型,即 A。运行时类型 ofright是参数的实际类型,即 A2(请参阅输出,它with argument A2在那里说明)。

翻翻过去那场雪

Java 有A,它被称为single dispatch:方法重载由编译器在编译时选择(将 的编译时类型与 的编译时类型right提供的方法相匹配left)方法调用发生在运行时类型上left——因为方法不会消失,left当然有一个方法具有在编译时选择的相同签名。此行为算作“调度”,并且因为它仅取决于left(在运行时),所以它是“单一的”。使用内置println(Object)and的超级简单演示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);Objectprintln(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);}这一个导致abcabcasprintln是手动选择的,使用参数的运行时类型。所以如果有人真的需要它,在 Java 中是可以做到的,但它不会自动发生。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java