While studying Java tutorials, Reflection and Late Binding have confused me. In some tutorials, they have written that they are both the same, and that there isn't any difference between Reflection and Late Binding. But other tutorials say that there is a difference.
I am confused, so can someone please explain what Reflection and Late Binding are in Java, and if posible, please give me some real world examples of both.
Thanks..
Java uses late-binding to support polymorphism; which means the decision of which of the many methods should be used is deferred until runtime.
Take the case of N classes implementing an abstract method of an interface (or an abstract class, fwiw).
public interface IMyInterface {
public void doSomething();
}
public class MyClassA implements IMyInterface {
public void doSomething(){ ... }
}
public class MyClassB implements IMyInterface {
public void doSomething(){ ... }
}
public class Caller {
public void doCall(IMyInterface i){
// which implementation of doSomething is called?
// it depends on the type of i: this is late binding
i.doSomething();
}
}
Reflection is used instead to describe code which is able to inspect other code, ie. to know which methods or attributes are available in a class, to call a method (or load a class) by name, and doing a lot of very interesting things at runtime.
A very nice explaination of reflection is here: What is reflection and why is it useful?
Late binding (also known as dynamic dispatch) does not need reflection -- it still needs to know which member to dynamically bind to at compile-time (i.e. the signature of the member is known at compile-time), even though the binding to overridden members happens at run-time.
When doing reflection, you don't even know which member you're using (not even the name is known at compile-time, let alone the signature) -- everything happens at run-time, so it's a lot slower.
Real world examples:
If you build your project with jdesktop 0.8, but ship with jdesktop 0.9, your code will still use the 0.9 features, because it takes advantage of late binding, i.e. the code that your code calls is the version that is loaded by the class loader, irrespective of the version that it was compiled against. (This is as opposed to linkers, which embed the compile-time version of the called code into the application.)
For reflection, let's say you are trying to target Java 1.5 and 1.6, but want to use tab components in 1.6 if they are available, then you'll check for their presence by using reflection on the JTabbedPane class to find the setTabComponentAt method. In this case you're building against Java 1.5, which doesn't have those features at all, so you can't call them directly or the compile will fail. However if on the end-user's system you find yourself running against 1.6 (late binding comes into play here) you can use reflection to call methods that didn't exist in 1.5.
They are related; many uses of reflection rely on late binding to be useful, but they are fundamentally different aspects of the language and its implementation.
One important issue which is addressed by "Late Binding" is the polymorphism, i.e. that the call of the proper overriden method along your class hierachy is determined during the run-time, not during compilation. Reflection is the feature to gather and manipulate information about your objects during run-time. E.g. you can get all attributes or method names of an object using its 'Class' attribute during the runtime and call those methods or manipulate its attributes.
In following code you can dynamically create a new object by the means of reflection (see how the constructor is retrieved and accessed using a Class, instead of using simply something like object obj = new MyClass( "MyInstance" ) ). In a similar way it is possible to access other constructor forms, methods and attributes. For more information about reflection in java visit: http://java.sun.com/developer/technicalArticles/ALT/Reflection/
... in some method of some class ...
Class c = getClass();
Constructor ctor = c.getConstructor( String.class );
Object obj = ctor.newInstance( "MyInstance" );
I have to disagree with most of the responses here -
Everyone calls what Java does in terms of zeroing in on a method implementation at runtime as late binding, but in my opinion its not correct to use the term late binding for what java does.
Late binding implies absolutely no checks on a method call at compile time and no compilation errors if the method does not exist.
Java however will throw a compile error if the method does not exist somewhere in the type hierarchy of the type qualifying the method call (being somewhat approximate when describing the behavior here). This is not pure traditional late binding.
What Java does in a normal non private non final non static method call would be better termed as dynamic dispatch.
However if we use reflection in Java, then Java does perform pure late binding as the compiler simply cannot verify if the called method exists or not.
Here is an example:
class A
{
public void foo()
{
System.out.println("Foo from A");
}
}
class B extends A
{
public void foo()
{
System.out.println("Foo from B");
}
}
public class C
{
public static void main(String [] args)
{
A a=new A();
B b=new B();
A ref=null;
Class ref1 = null;
ref1 = b.getClass();
ref.foo1();//will not compile because Java in this normal method
//call does some compile time checks for method and method
//signature existence. NOT late binding in its pure form.
try {
ref1.getMethod("foo1").invoke(null); //will throw a
//NoSuchMethodException at runtime, but compiles perfectly even
//though foo1 does not exist. This is pure late binding.
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Related
I have some code with a method reference that compiles fine and fails at runtime.
The exception is this:
Caused by: java.lang.invoke.LambdaConversionException: Invalid receiver type class redacted.BasicEntity; not a subtype of implementation type interface redacted.HasImagesEntity
at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:233)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
at java.lang.invoke.CallSite.makeSite(CallSite.java:289)
The class triggering the exception:
class ImageController<E extends BasicEntity & HasImagesEntity> {
void doTheThing(E entity) {
Set<String> filenames = entity.getImages().keySet().stream()
.map(entity::filename)
.collect(Collectors.toSet());
}
}
The exception is thrown trying to resolve entity::filename. filename() is declared in HasImagesEntity. As far as I can tell, I get the exception because the erasure of E is BasicEntity and the JVM doesn't (can't?) consider other bounds on E.
When I rewrite the method reference as a trivial lambda, everything is fine. It seems really fishy to me that one construct works as expected and its semantic equivalent blows up.
Could this possibly be in the spec? I'm trying very hard to find a way for this not to be a problem in the compiler or runtime, and haven't come up with anything.
Here is a simplified example which reproduces the problem and uses only core Java classes:
public static void main(String[] argv) {
System.out.println(dummy("foo"));
}
static <T extends Serializable&CharSequence> int dummy(T value) {
return Optional.ofNullable(value).map(CharSequence::length).orElse(0);
}
Your assumption is correct, the JRE-specific implementation receives the target method as a MethodHandle which has no information about generic types. Therefore the only thing it sees is that the raw types mismatch.
Like with a lot of generic constructs, there is a type cast required on the byte code level which doesn’t appear in the source code. Since LambdaMetafactory explicitly requires a direct method handle, a method reference which encapsulates such a type cast cannot be passed as a MethodHandle to the factory.
There are two possible ways to deal with it.
First solution would be to change the LambdaMetafactory to trust the MethodHandle if the receiver type is an interface and insert the required type cast by itself in the generated lambda class instead of rejecting it. After all, it does similar for parameter and return types already.
Alternatively, the compiler would be in charge to create a synthetic helper method encapsulating the type cast and method call, just like if you had written a lambda expression. This is not a unique situation. If you use a method reference to a varargs method or an array creation like, e.g. String[]::new, they can’t be expressed as direct method handles and end up in synthetic helper methods.
In either case, we can consider the current behavior a bug. But obviously, compiler and JRE developers must agree on which way it should be handled before we can say on which side the bug resides.
I've just fixed this issue in JDK9 and JDK8u45. See this bug. The change will take a little while to percolate into promoted builds.
Dan just pointed me at this Stack Overflow question, so I'm adding this note When you find bugs, please do submit them.
I addressed this by having the compiler create a bridge, as is the approach for many cases of complex method references. We are also examining spec implications.
This bug is not entirely fixed. I just ran into a LambdaConversionException in 1.8.0_72 and saw that there are open bug reports in Oracle's bug tracking system: link1, link2.
(Edit: The linked bugs are reported to be closed in JDK 9 b93)
As a simple workaround I avoid method handles. So instead of
.map(entity::filename)
I do
.map(entity -> entity.filename())
Here is the code for reproducing the problem on Debian 3.11.8-1 x86_64.
import java.awt.Component;
import java.util.Collection;
import java.util.Collections;
public class MethodHandleTest {
public static void main(String... args) {
new MethodHandleTest().run();
}
private void run() {
ComponentWithSomeMethod myComp = new ComponentWithSomeMethod();
new Caller<ComponentWithSomeMethod>().callSomeMethod(Collections.singletonList(myComp));
}
private interface HasSomeMethod {
void someMethod();
}
static class ComponentWithSomeMethod extends Component implements HasSomeMethod {
#Override
public void someMethod() {
System.out.println("Some method");
}
}
class Caller<T extends Component & HasSomeMethod> {
public void callSomeMethod(Collection<T> components) {
components.forEach(HasSomeMethod::someMethod); // <-- crashes
// components.forEach(comp -> comp.someMethod()); <-- works fine
}
}
}
I found a workaround for this was swapping the order of the generics. For instance, use class A<T extends B & C> where you need to access a B method, or use class A<T extends C & B> if you need to access a C method. Of course, if you need access to methods from both classes, this won't work. I found this useful when one of the interfaces was a marker interface like Serializable.
As for fixing this in the JDK, the only info I could find were some bugs on openjdk's bug tracker that are marked resolved in version 9 which is rather unhelpful.
For the record, the Eclipse compiler of Eclipse 2021-09 (4.21.0) still seems to have this (or a very similar) bug, which I've reported here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=577466
So, if you're developing with Eclipse, it might be this error still persists when developing (using the Eclipse compiler), even when at build time, it is absent (using javac via Maven or Gradle, etc.).
As succinctly described here, overriding private methods in Java is invalid because a parent class's private methods are "automatically final, and hidden from the derived class". My question is largely academic.
How is it not a violation of encapsulation to not allow a parent's private method to be "overridden" (ie, implemented independently, with the same signature, in a child class)? A parent's private method cannot be accessed or inherited by a child class, in line with principles of encapsulation. It is hidden.
So, why should the child class be restricted from implementing its own method with the same name/signature? Is there a good theoretical foundation for this, or is this just a pragmatic solution of some sort? Do other languages (C++ or C#) have different rules on this?
You can't override a private method, but you can introduce one in a derived class without a problem. This compiles fine:
class Base
{
private void foo()
{
}
}
class Child extends Base
{
private void foo()
{
}
}
Note that if you try to apply the #Override annotation to Child.foo() you'll get a compile-time error. So long as you have your compiler/IDE set to give you warnings or errors if you're missing an #Override annotation, all should be well. Admittedly I prefer the C# approach of override being a keyword, but it was obviously too late to do that in Java.
As for C#'s handling of "overriding" a private method - a private method can't be virtual in the first place, but you can certainly introduce a new private method with the same name as a private method in the base class.
Well, allowing private methods to be overwritten will either cause a leak of encapsulation or a security risk. If we assume that it were possible, then we’d get the following situation:
Let's say that there's a private method boolean hasCredentials() then an extended class could simply override it like this:
boolean hasCredentials() { return true; }
thus breaking the security check.
The only way for the original class to prevent this would be to declare its method final. But now, this is leaks implementation information through the encapsulation, because a derived class now cannot create a method hasCredentials any more – it would clash with the one defined in the base class.
That’s bad: lets say this method doesn’t exist at first in Base. Now, an implementor can legitimately derive a class Derived and give it a method hasCredentials which works as expected.
But now, a new version of the original Base class is released. Its public interface doesn’t change (and neither do its invariants) so we must expect that it doesn’t break existing code. Only it does, because now there’s a name clash with a method in a derived class.
I think the question stems from a misunderstanding:
How is it /not/ a violation of encapsulation to not allow a parent's private method to be "overridden" (ie, implemented independently, with the same signature, in a child class)
The text inside the parentheses is the opposite of the text before it. Java does allow you to “independently implement [a private method], with the same signature, in a child class”. Not allowing this would violate encapsulation, as I’ve explained above.
But “to not allow a parent's private method to be "overridden"” is something different, and necessary to ensure encapsulation.
"Do other languages (C++ or C#) have different rules on this?"
Well, C++ has different rules: the static or dynamic member function binding process and the access privileges enforcements are orthogonal.
Giving a member function the private access privilege modifier means that this function can only be called by its declaring class, not by others (not even the derived classes). When you declare a private member function as virtual, even pure virtual (virtual void foo() = 0;), you allow the base class to benefit from specialization while still enforcing the access privileges.
When it comes to virtual member functions, access privileges tells you what you are supposed to do:
private virtual means that you are allowed to specialize the behavior but the invocation of the member function is made by the base class, surely in a controlled fashion
protected virtual means that you should / must invoke the upper class version of the member function when overriding it
So, in C++, access privilege and virtualness are independent of each other. Determining whether the function is to be statically or dynamically bound is the last step in resolving a function call.
Finally, the Template Method design pattern should be preferred over public virtual member functions.
Reference: Conversations: Virtually Yours
The article gives a practical use of a private virtual member function.
ISO/IEC 14882-2003 §3.4.1
Name lookup may associate more than one declaration with a name if it finds the name to be a function name; the declarations are said to form a set of overloaded functions (13.1). Overload resolution (13.3) takes place after name lookup has succeeded. The access rules (clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded. Only after name lookup, function overload resolution (if applicable) and access checking have succeeded are the attributes introduced by the name’s declaration used further in expression processing (clause 5).
ISO/IEC 14882-2003 §5.2.2
The function called in a member function call is normally selected according to the static type of the object expression (clause 10), but if that function isvirtualand is not specified using aqualified-idthen the function actually called will be the final overrider (10.3) of the selected function in the dynamic type of the object expression [Note: the dynamic type is the type of the object pointed or referred to by the current value of the object expression.
A parent's private method cannot be accessed or inherited by a child class, inline with principles of encapsulation. It is hidden.
So, why should the child class be
restricted from implementing its own
method with the same name/signature?
There is no such restriction. You can do that without any problems, it's just not called "overriding".
Overridden methods are subject to dynamic dispatch, i.e. the method that is actually called is selected at runtime depending on the actual type of the object it's called on. With private method, that does not happen (and should not, as per your first statement). And that's what is meant by the statement "private methods can't be overridden".
I think you're misinterpreting what that post says. It's not saying that the child class is "restricted from implementing its own method with the same name/signature."
Here's the code, slightly edited:
public class PrivateOverride {
private static Test monitor = new Test();
private void f() {
System.out.println("private f()");
}
public static void main(String[] args) {
PrivateOverride po = new Derived();
po.f();
});
}
}
class Derived extends PrivateOverride {
public void f() {
System.out.println("public f()");
}
}
And the quote:
You might reasonably expect the output to be “public f( )”,
The reason for that quote is that the variable po actually holds an instance of Derived. However, since the method is defined as private, the compiler actually looks at the type of the variable, rather than the type of the object. And it translates the method call into invokespecial (I think that's the right opcode, haven't checked JVM spec) rather than invokeinstance.
It seems to be a matter of choice and definition. The reason you can't do this in java is because the specification says so, but the question were more why the specification says so.
The fact that C++ allows this (even if we use virtual keyword to force dynamic dispatch) shows that there is no inherent reason why you couldn't allow this.
However it seem to be perfectly legal to replace the method:
class B {
private int foo()
{
return 42;
}
public int bar()
{
return foo();
}
}
class D extends B {
private int foo()
{
return 43;
}
public int frob()
{
return foo();
}
}
Seems to compile OK (on my compiler), but the D.foo is not related to B.foo (ie it doesn't override it) - bar() always return 42 (by calling B.foo) and frob() always returns 43 (by calling D.foo) no matter whether called on a B or D instance.
One reason that Java does not allow override the method would be that they didn't like to allow the method to be changed as in Konrad Rudolph's example. Note that C++ differs here as you need to use the "virtual" keyword in order to get dynamic dispatch - by default it hasn't so you can't modify code in base class that relies on the hasCredentials method. The above example also protects against this as the D.foo does not replace calls to foo from B.
When the method is private, it's not visible to its child. So there is no meaning of overriding it.
I apologize for using the term override incorrectly and inconsistent with my description. My description describes the scenario. The following code extends Jon Skeet's example to portray my scenario:
class Base {
public void callFoo() {
foo();
}
private void foo() {
}
}
class Child extends Base {
private void foo() {
}
}
Usage is like the following:
Child c = new Child();
c.callFoo();
The issue I experienced is that the parent foo() method was being called even though, as the code shows, I was calling callFoo() on the child instance variable. I thought I was defining a new private method foo() in Child() which the inherited callFoo() method would call, but I think some of what kdgregory has said may apply to my scenario - possibly due to the way the derived class constructor is calling super(), or perhaps not.
There was no compiler warning in Eclipse and the code did compile. The result was unexpected.
Beyond anything said before, there's a very semantic reason for not allowing private methods to be overridden...THEY'RE PRIVATE!!!
If I write a class, and I indicate that a method is 'private', it should be completely unseeable by the outside world. Nobody should be able access it, override it, or anything else. I simply ought to be able to know that it is MY method exclusively and that nobody else is going to muck with it or depend on it. It could not be considered private if someone could muck with it. I believe that it's that simple really.
A class is defined by what methods it makes available and how they behave. Not how those are implemented internally (e.g. via calls to private methods).
Because encapsulation has to do with behavior and not implementation details, private methods have nothing to do with the idea encapsulation. In a sense, your question makes no sense. It's like asking "How is putting cream in coffee not a violation of encapsulation?"
Presumably the private method is used by something that is public. You can override that. In doing so, you've changed behavior.
There are too many associated names: Early and Late Binding, Static and Dynamic Dispatch, Runtime vs. Compile-time Polymorphism, etc. that I don't understand the difference.
I found a clear explanation, but is it correct? I'll paraphrase JustinC:
Binding: is determining the type of a variable (object?). If it's done at compile time, its early binding. If it's done at run time, it's late binding.
Dispatch: is determining which method matches the method call. Static Dispatch is computing methods at compile time, whereas dynamic dispatch is doing it at run time.
Is Binding matching up primitive and reference variables with primitive values and objects respectively?
Edit: Please give me some clear reference material so I can read more about this.
I believe the confusion typically comes from how overloaded these terms are.
We program our programs in a high level language, and either a compiler or an interpreter must transform that into something a machine actually understands.
In coarse terms, you can picture a compiler transforming our method code into some form of machine code. If the compiler knew at that point exactly where in the memory that method would reside when we run our program later, then it could safely go and find every method invocation of this compiled method and replace it with a jump to this address where the compiled code resides, right?.
Well, materializing this relationship is what I understand as binding. This binding, though, could happen at different moments, for example at compile time, linking time, load time, or at run time depending on the design of the language.
The terms static and dynamic are generally used to refer to things bound before run time and at run time, respectively.
Later binding times are associated with greater flexibility, earlier binding times are associated with greater efficiency. Language designers have to balance these two aspects when they're creating a language.
Most object-oriented programming languages support subtype polymorphism. In these languages, virtual methods are bound at runtime depending on the dynamic type of the object at that point. In other words, virtual method invocations are dispatched to the appropriate implementation at runtime based on the dynamic type of the object implementation involved and not based solely on its static type reference.
So, in my opinion, you must first bind the method invocation to a specific implementation or execution address, and then you can dispatch an invocation to it.
I had answered a very similar question in the past in which I demonstrate with examples how this happens in Java.
I would also recommend reading the book Programming Language Pragmatics. It is a great reference to learn all this kind of stuff from a theoretical standpoint.
When you're looking for "low level" definitions, probably the only legitimate source is our old friend - the JLS. Though it does not give a clear definition in this case, the context in which it uses each term might be enough.
Dispatch
This term is indeed mentioned in procedures of determining which method to call.
15.12.2. Compile-Time Step 2: Determine Method Signature
The second step searches the type determined in the previous step for
member methods. This step uses the name of the method and the argument
expressions to locate methods that are both accessible and applicable,
that is, declarations that can be correctly invoked on the given
arguments.
There may be more than one such method, in which case the
most specific one is chosen. The descriptor (signature plus return
type) of the most specific method is the one used at run time to
perform the method dispatch. A method is applicable if it is
applicable by one of strict invocation
The elaboration on what is the "most specific" method is done in 15.12.2.5 Choosing the Most Specific Method.
As for "dynamic dispatch",
JLS 12.5. Creation of New Class Instances:
Unlike C++, the Java programming language does not specify altered
rules for method dispatch during the creation of a new class instance.
If methods are invoked that are overridden in subclasses in the object
being initialized, then these overriding methods are used, even before
the new object is completely initialized.
It includes
Example 12.5-2. Dynamic Dispatch During Instance Creation
class Super {
Super() {
printThree();
}
void printThree() {
System.out.println("three");
}
}
class Test extends Super {
int three = 3;
void printThree() {
System.out.println(three);
}
public static void main(String[] args) {
Test t = new Test();
t.printThree();
}
}
Output:
0
3
This happens because during the constructor call chain, Super's constructor calls printThree, but due to dynamic dispatch the method in Test is called, and that is before the field is initialized.
Binding
This term is used in contexts of class member access.
Example 15.11.1-1. Static Binding for Field Access demonstrates early and late bindings. I will summarize the examples given there for the lazy of us:
class S {
int x = 0;
int z() { return x; }
}
class T extends S {
int x = 1;
int z() { return x; }
}
public class Test1 {
public static void main(String[] args) {
S s = new T();
System.out.println("s.x=" + s.x);
System.out.println("s.x=" + s.z());
}
}
Output:
s.x=0
s.x=1
Showing that the field uses "early binding", while the instance method uses "late binding":
This lack of dynamic lookup for field accesses allows programs to be run efficiently with
straightforward implementations. The power of late binding and overriding is available, but
only when instance methods are used.
Binding is also used in regards to determining the type of a generic,
8. Classes
Classes may be generic (§8.1.2), that is, they may declare type variables whose bindings may differ among different instances of the class.
Meaning that if you create 2 instances of List<String>, the bindings of String in both instances are different from each other.
This also applies to raw types:
4.8. Raw Types
class Outer<T>{
T t;
class Inner {
T setOuterT(T t1) { t = t1; return t; }
}
}
The type of the member(s) of Inner depends on the type parameter of Outer. If Outer is raw, Inner must be treated as raw as well, as there is no valid binding for T.
Meaning that declaring Outer outer (this will generate a raw type warning) does not allow to determine the type of T (obviously - it wasn't defined in the declaration).
These are general terms, you can summarize it in this way: when some thing(method or object) is static/early it means that thing is configured in compile-time and there is no ambiguity in run time for example in the following code:
class A {
void methodX() {
System.out.print("i am A");
}
}
If we create an instance of A and call methodX(), nothing is ambitious and everythin is configured at compile time but if we have the following code
class B extends A {
void methodX() {
System.out.print("i am B");
}
}
....
A objX= new B();
objX.methodX();
Out put of method x is not known until runtime, so this method is dynamically binded/dispatched (we can use the term dispatched instead of bind for methods link).
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(); }
}
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.)
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?
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.
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.
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.
class A { void F() { System.out.println("a"); }}
class B extends A { void F() { System.out.println("b"); }}
public class X {
public static void main(String[] args) {
A objA = new B();
objA.F();
}
}
Here, F() is being invoked dynamically, isn't it?
This article says:
... the Java bytecode doesn’t support
dynamic method invocation. There are
three supported invocations modes :
invokestatic, invokespecial,
invokeinterface or invokevirtual.
These modes allows to call methods
with known signature. We talk of
strongly typed language. This allows
to to make some checks directly at
compile time.
On the other side, the dynamic
languages use dynamic types. So we can
call a method unknown at the compile
time, but that’s completely impossible
with the Java bytecode.
What am I missing?
You are confusing dynamic invocation with dynamic binding..
The first one allows the type checker to accept programs in which you are not sure if a method will be present on an object at run-time, while dynamic binding just chooses the right implementation according to the runtime type of the object but maintaining the statically type checking.
What does it mean?
It means that in your example, Java will call the implementation on object B because the runtime type of the objA variable is B; and it will compile because it knows that a B is a A so the method invocation won't fail at runtime (objA will have a F implementation for sure).
With dynamic invocation instead it won't check at compile time that the type of the object on which you are calling F contains that method, of course it will raise an exception if during execution the method won't be available on specified object.
Just for trivia: the invokedynamic feature will be added with Java7 because many scripting languages have been written to work on top of JVM and the lack of a dynamic invocation feature forced the developers of these languages to add a middle layer between the script and the real JVM that cares about dynamic invocation using the reflection. Of course this approach causes a lot of overhead (think about Grovvy's MetaClass), that's why Sun decided to give them a help..
In your example the correct method is called because polymorphically the instance of B appears like an instance of A. The method can be located by examining the runtime type of the object; that is, B; as opposed to the compile-time type of the object reference, A. The other important part is the signature of method - these must always match (polymorphically of course).
This differs from dynamic languages because in those there is essentially no compile-time for the object - and everything must be resolved at runtime.
In fact, what you're missing is that this is the part of 'invokevirtual' which is explained in the article.
You're simply overriding the method and that uses a virtual method table to invoke the correct method.
I wouldn't call your example "dynamic", rather virtual. Because at compile time the method name and signature is known (and its existence is checked by the compiler). The only that is resolved at runtime is the concrete implementation to be used for that method.
A more proper example of "dynamic" method invocation would involve reflection, (see the Method class ). In that way, methods whose existence are unkown at compile type can be invoked in runtime (this is extensively used by frameworks, not so much by application code).
The article you mention seems a little misleading in that respect. But it's true that the signature of the methods you explicitly call must be known/checked in compile time, and so, in that sense, Java is not dynamic.
You can make functional interfaces.
class Logger {
private BiConsumer<Object, Integer> logger = null;
// ...
private Logger(Object logger) {
this.akkaLogger = (LoggingAdapter) logger;
this.logger = (message, level) -> {
switch (level) {
case INFO: akkaInfo(message);
break;
case DEBUG: akkaDebug(message);
break;
case ERROR: akkaError(message);
break;
case WARN: akkaWarn(message);
break;
}
};
}
private Logger() {
this.logger = (message, level) -> System.out.println(message);
}
// ...
}