简体   繁体   English

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

[英]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: 怎么解决:

  • A) basing on runtime type of left and compile-time of right A)基于左边的运行时类型和右边的编译时间
  • B) basing on compile-time type of left and runtime of right B)基于左边的编译时类型和右边的运行时
  • C) basing on compile-time type of left and compile-time of right C)基于左侧的编译时类型和右侧的编译时间
  • D) basing on runtime type of left and runtime of right D)基于左边的运行时类型和右边的运行时

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 of right . E)基于编译时AND运行时类型的leftright编译时类型。

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 ,它叫做单调度

  • the method overload is selected by the compiler, at compile-time (matching the compile-time type of right to the methods offered by the compile-time type of left ) 方法重载由编译器在编译时选择(将编译时类型的right与编译时类型left提供的方法相匹配)
  • the method invocation happens on the runtime type of 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. BC可能不存在。

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);
}

This one results in 导致

 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM