Saturday, June 21, 2008

Dynamic Binding vs Static Binding in Java


Difference between Dynamic Binding & Static Binding in Java

Dynamic Binding or Late Binding

Dynamic Binding refers to the case where compiler is not able to resolve the call and the binding is done at runtime only. Let's try to understand this. Suppose we have a class named 'SuperClass' and another class named 'SubClass' extends it. Now a 'SuperClass' reference can be assigned to an object of the type 'SubClass' as well. If we have a method (say 'someMethod()') in the 'SuperClass' which we override in the 'SubClass' then a call of that method on a 'SuperClass' reference can only be resolved at runtime as the compiler can't be sure of what type of object this reference would be pointing to at runtime.

...
SuperClass superClass1 = new SuperClass();
SuperClass superClass2 = new SubClass();
...

superClass1.someMethod(); // SuperClass version is called
superClass2.someMethod(); // SubClass version is called
....

Here, we see that even though both the object references superClass1 and superClass2 are of type 'SuperClass' only, but at run time they refer to the objects of types 'SuperClass' and 'SubClass' respectively.

Hence, at compile time the compiler can't be sure if the call to the method 'someMethod()' on these references actually refer to which version of the method - the super class version or the sub class version.

Thus, we see that dynamic binding in Java simply binds the method calls (inherited methods only as they can be overriden in a sub class and hence compiler may not be sure of which version of the method to call) based on the actual object type and not on the declared type of the object reference.

Static Binding or Early Binding

If the compiler can resolve the binding at the compile time only then such a binding is called Static Binding or Early Binding. All the instance method calls are always resolved at runtime, but all the static method calls are resolved at compile time itself and hence we have static binding for static method calls. Because static methods are class methods and hence they can be accessed using the class name itself (in fact they are encourgaed to be used using their corresponding class names only and not by using the object references) and therefore access to them is required to be resolved during compile time only using the compile time type information. That's the reason why static methods can not actually be overriden. Read more - Can you override static methods in Java?

Similarly, access to all the member variables in Java follows static binding as Java doesn't support (in fact, it discourages) polymorphic behavior of member variables. For example:-

class SuperClass{
...
public String someVariable = "Some Variable in SuperClass";
...
}

class SubClass extends SuperClass{
...
public String someVariable = "Some Variable in SubClass";
...
}
...
...

SuperClass superClass1 = new SuperClass();
SuperClass superClass2 = new SubClass();

System.out.println(superClass1.someVariable);
System.out.println(superClass2.someVariable);
...

Output:-
Some Variable in SuperClass
Some Variable in SuperClass

We can observe that in both the cases, the member variable is resolved based on the declared type of the object reference only, which the compiler is capable of finding as early as at the compile time only and hence a static binding in this case. Another example of static binding is that of 'private' methods as they are never inherited and the compile can resolve calls to any private method at compile time only.


Update[June 24, 2008]: Read more to understand how field hiding in Java works? How is it different from static method hiding? - Field Hiding in Java >>

Liked the article? You may like to Subscribe to this blog for regular updates. You may also like to follow the blog to manage the bookmark easily and to tell the world that you enjoy GeekExplains. You can find the 'Followers' widget in the rightmost sidebar.



Share/Save/Bookmark


15 comments:

matt said...

Would this still compile? Seems like the compiler should warn if member vars are overridden?

Rohit said...

Yes Matt. It'll compile. I just checked on my JDK 1.5 compiler. The compiler won't give any warning - not at least with the typical settings. I don't know what will happen if we increase the warning level settings of the compiler.

Geek said...

Matt: Yes... the code will compile. Member overriding is permitted in Java. In case of instance members, there will be overriding and in case of static members, it would be hiding.

A subclass can inherit members (fields, methods, and nested classes) from its superclass. Constructors are not members, so they are not inherited (But they can be invoked from subclasses). I hope this helps you getting your answer. Thanks for your visit.

Rohit: Thank you for posting the answer.

Keep visiting/posting!

Geek said...

Matt: By writing 'Member Overriding is permitted in Java' in my above comment I meant that you won't get a compiler error while trying that, but fields are not actually overridden instead they are hidden. Similarly 'Instance Members' truely mean only 'Instance methods' in that comment as only they are overridden in Java. Posted a new article illustrating Field Hiding in Java (http://geekexplains.blogspot.com/2008/06/field-hiding-in-java-fields-are-only.html). Hope you'll find this of some help.

Anonymous said...

Hi Geek,
Could you tell me how the compiler translates the following at compile time?
SuperClass superClass1 = new SuperClass();
SuperClass superClass2 = new SubClass();

Geek said...

What exactly you want to know about the translation of these two lines? Like any other code-segment, this will also go through the various compilation phases like Lexical Analysis, Syntax Analysis (Parsing), Semantic Analysis, Intermediate Code Generation, Optimization (optional), and finally the actual Code Generation (bytecode in case of Java).

As you can see that there is nothing wrong with the symbols, keywords, and language syntax in the two statements so you can expect them to pass the Parsing phase easily. Now during the Semantic Analysis, the Java compiler allows these two statements as it knows that an object reference of type 'super class' can point to an object of either that class or any of its 'sub-classes'.

Out of the two statement - the first one has a super class type reference pointing to an object of the same class and the second statement has a super class type reference pointing to an object of a sub-class of that type. Both cases are valid, so no problem. All right?

Does this help? Otherwise, please help me understanding the actual query by posting some more detail. Keep visiting/posting!

Neem said...

With reference to a previous question in the Comments section,

SuperClass superClass2 = new SubClass();

What is the main advantage of writing like this? Somehow, am not clear with this polymorphic programming. I've read in many articles that we should code to interfaces and not to implementation because doing so would give the flexibility to change implementation by merely changing constructor.

Your example also, codes to interface. But we instantiate subclass in the above code. I don't get the advantage here. subclass is hardcoded, isn't it? If I've to change to some other class tomorrow, I need to modify my code. So, what is the advantage?

Geek said...

The article just explains the differences between dynamic binding and static binding using easily understandable code-snippets. It only talks about how exactly these two happen internally and how do they differ.

Just to be clear, by this I'm not supporting the practice of implementing dynamic binding without using 'interfaces'.

I believe, it depends upon the actual situation for someone to decide whether to use 'interfaces' or not.

As you have rightly said, in most of the cases we would be implementing a polymorphic behavior using interfaces only - for the advantage of offering more flexibility to the consumers with their multiple implementations.

However, there can definitely be some (relatively fewer) situations where you would probably not like to go the 'interfaces' way. For example:-

(i) If the implementation is internal to your class/app.

There is hardly any need of exposing a public face (interface) for something internal to your code/app. Additionally, going via 'interfaces' would only add unnecessary overhead due to extra indirection (though, I agree that the overhead has become very low these days with faster JVMs, but as you can understand it'll never be zero).

(ii) If there is very little (only few methods) the consumers would like to implement themselves, that too, not always.

It would become even more unnecessary when you know that very few consumers would like to use their own implementation. Those who might need, can simply extend the class and override those methods.

Hope it helps. Keep posting!

Anonymous said...

If I have a method that calls a static method in a third party library (jar) file like this:

public static Collection getCollection(Iterator iterator){
Collection collection = new ArrayList();
// logic
return collection;
}

My code calls this static method. Then the third party sends out an updated jar file and the static method now looks like this:

public static ArrayList getCollection(Iterator iterator){
ArrayList list = new ArrayList();
// logic
return list;
}

My code is not recompiled, we just replaced the old jar with the new one but now I get a java.lang.NoSuchMethodError.

Can you explain why this would be - the signatures are equivalent in that I was expecting a Collection but now I get a concrete implementation.

NOTE that if the method in the jar was not static, no error.

Geek said...

Because for 'static' methods, the binding happens at the compile-time itself. In absence of a re-compilation your bytecodes are still expecting a method having 'Collection' as the return data-type and not the one with 'ArrayList' as the return type.

For a compile-time binding there is nothing left to be resolved at run-time and hence the JRE will throw NoSuchMethodError if the signature has changed - even if the changed one is compatible with the previous one. This means that for a static method, the JRE simply tries to find the method with the already bind signature without any compatibility check, on failing which, it throws the error.

It's always advisable to re-compile the app whenever some JARs and/or CLASSPATH entries change. The code will compile (and subsequently run) fine if no incompatible changes have been made in the changed JARs/CLASSPATH-entries.

In case of an 'instance' method the resolution happens at run-time and hence the JRE can easily accept a compatible signature change.

Hope this helps. Keep posting!

Anup said...

Nicely Explained :Keep Going

maya said...

Means ,It will always give the output of super class?

Geek said...

Maya, I didn't really get your question... suggest you read the article one more time and if you still have doubts then elaborate the query little more please.

Anonymous said...

Thanks!! nicely explained
--vivek

neale said...

This website has very good content, efficiently written. i'll come back to read more great content articles from you.

www.n8fan.net