Late Binding in Java

2019-02-12 19:32发布

问题:

I have searched through all the similar questions on late binding on stack overflow, and I would severely disagree with anyone who marks this question as a duplicate. First off, i found this example on another question, but I do not understand how I am supposed to know when something is decided during compile time and when something is decided during run time. Basically, the crux of my question boils down to two things:

  • What in this example must bring me to the logical conclusion that one method is late binding and another is early binding

  • How do I know when the decision about which version of a method to execute is decided during run-time or compile time in Java

Code:

class A
{
    public void foo()
    {
        System.out.println("Class A");
    }
}

class B extends A
{
    public void foo()
    {
        System.out.println("Class B");
    }
}

public class C
{
    public static void main(String [] args)
    {
        A a=new A();
        B b=new B();
        A ref=null;

        /* 
            early binding  --- calls method foo() of class A and
            decided at compile time
        */ 
         a.foo(); 

        /* early binding --- calls method foo() of class B and
            decided at compile time
        */
          b.foo(); 

        /* late  binding --- --- calls method foo() of class B and
           decided at Run time
     */ 
        ref=b;
        ref.foo(); }
}

回答1:

Wrong on all counts. The method to be called is decided at runtime, in every case here, based on the runtime type of the object. The only decisions made at compile time are for calls to final, private, or static methods, or choices among a set of overloaded methods (which could still lead to runtime choices if the overloaded methods are not final, private, or static.)



回答2:

Java uses late binding for all non-final, non-private instance methods. This is how polymorphism is implemented. All of the calls you commented on are determined at run time.

In

A a=new A();
a.foo(); 

a is referencing an A object so A's implementation will be found, bound and used.

In

B b=new B();
b.foo();

b is referencing a B object so B's implementation will be found, bound, and used.

In

ref=b;
ref.foo();

ref is referencing a B object so B's implementation will be found, bound, and used.

The static (declared) type of the variable is only used by the compiler to verify that such a method is accessible on that type.

Related:

  • What is early and late binding?


回答3:

All the answers here are mostly correct, but there is one key point missing regarding late binding in Java.
Java does not perform "by the book" late binding if we go by the definition of late binding. Late binding in its book definition form means that the compiler should perform no argument checks, no type checks on a method call and should leave it all to the runtime - because possibly the compiler does not have access to the method implementation code (for example in COM programming). Java however at compile time does verify, even in a polymorphic scenario, that the method being called and the method signature does exist somewhere in the type hierarchy of the expression that qualifies the method. So for example, lets say I call a method foo1 on ref that does not exist in either A or B:

A ref=null;
ref=new B();
ref.foo1();
//This will not compile in Java, because java will check at compile time
//for the method foo1 in the type hierarchy of A, which is the type of the 
// variable ref at compile time.
//In pure late binding, however this would pass compilation and 
//throw an error at runtime.

In a pure late binding scenario, the determination of whether the method foo1() exists or not with the right number of arguments is made purely at runtime. However in Java, there is some level of checking done at compile time, to ensure that the method with the right number of arguments does exist somewhere in the type hierarchy.
The only time that I think Java does perform pure late binding is if one uses reflection to call a method. What Java does is better termed as dynamic dispatch rather than late binding, but everyone calls it late binding in Java and hence there is confusion.



回答4:

Consider the statement

 A ref; //reference of A
   ref = new B();//Object of B
      ref.f2();

Here ref is a reference of class A and it has address of object of class B f2() is a overridden method.

When compiler detects such a statement then it doesn't bind the function call with any definition. It only validates the call.

Binding of such calls is left for the runtime environment. At program runtime system identifies the datatype of the object and binds the function call with the function definition provided by the class of object. This type of binding between the function call and function defination is called as "late binding" or "runtime binding" or "runtime polymorphism" or "dynamic method dispatch".

go through this question and read my answer example is also given there.



回答5:

When you call a method on any object, always remember in inheritance "least modified version" of method will be called. This is nothing but dynamically picking the method version from the hierarchy.