Java Static and Dynamic Binding, Overloading

后端 未结 4 1332
-上瘾入骨i
-上瘾入骨i 2020-12-03 16:38

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         


        
相关标签:
4条回答
  • 2020-12-03 17:04

    Here is what's going on:

    stooge1.print(new Moe()); // All three have overload for Moe,
    // so the overload from the dynamic type of stooge1 gets called
    stooge1.print(new Curly()); // Compiler thinks stooge1 is Larry,
    // so it does not know that it has an overload for Curly.
    // It uses the overload for Larry instead, because Curly is a Larry
    stooge1.print(new Larry()); // Same logic as above applies.
    stooge2.print(new Curly()); // Compiler thinks stooge2 is Moe, so its only overload
    // is for Moe. Since the dynamic type is Larry, first overload is invoked
    

    The remaining three cases can be solved by applying the same logic as above.

    0 讨论(0)
  • 2020-12-03 17:11

    For #1, #2, #3 stooge1 is declared a Larry, so only methods available to Larry can be called.

    Passing a Moe will call print(Moe). Since the actual class is a Curly, it prints "Curly 1".

    Passing a Larry will call print(Larry), since that is a better match that print(Moe). This will print "Curly 2".

    Passing a Curly will also call print(Larry). Note that print(Curly) is unknown to stooge1, so it cannot be selected by the compiler. Therefore it also prints "Curly 2".

    Now try to figure out the rest.

    0 讨论(0)
  • 2020-12-03 17:18

    So this is a super confusing and awful example of something you should never do. The declared type of the variables matters for what signature methods have. So Larry doesn't have method that accepts a Curly, so the compiler considers the argument a Larry. But it gets dispatched to Curly's version of the method.

    So yeah, never ever do this =\

    0 讨论(0)
  • 2020-12-03 17:20

    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).

      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).

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

    (variable naming -> variable of type X holding instance of type Y is named xy).

    So, when we execute

    bc.print(new A());
    
    • static binding will try to find best print method signature available in class B which can handle instance of type A. In this case it will be print(A).
    • after that dynamic binding will search for code of this method in class C (since this is type of instance held by bc variable) which means we will see C.print(A).

    Similarly in case of bc.print(new C());

    • static binding will try to find best print method for C argument available in B class, which for C is print(B) (since there is no print(C) there and B is closest supertype).
    • So now dynamic binding knows which method to look for in C class (since this is instance which bc holds).

    So it will invoke C.print(B).

    0 讨论(0)
提交回复
热议问题