0

At first I'm a beginner
I have seen so much tutorials, read so much examples and tried to understand this topic even from the JLS, yet I still have some confusion or misunderstanding.

Let me show you the problem I can't understand.

Imagine we have three classes Parent, Child1, Child2 as follows:

class Parent {
    void doSmth(Object o) {
        System.out.println("Parent.doSmth");
    }
}

class Child1 extends Parent {
    void doSmth(Object o) {
        System.out.println("Child1.doSmth");
    }
}

class Child2 extends Parent {
    void doSmth(String s) {
        System.out.println("Child2.doSmth");
    }
}

class Test {
    public static void main(String[] args) {
        Parent p1 = new Child1();
        Parent p2 = new Child2();

        p1.doSmth("String");
        p2.doSmth("String");
    }
}

What I understood is, because the references of p1 and p2 are from the type Parent, then doSmth(Object) only will be visible to the compiler.

for p1.doSmth("String"); the compiler didn't bind it because there is an overriding method, so it just left it for the JVM to bind it in the runtime (dynamic binding).

while for p2.doSmth("String"); the compiler bound it because it found no overriding methods for it (static binding).

The question is, Is what I've said true? or do I have a misconception? if it's false, then please tell me what steps does the compiler take in such cases??
And if it's true, how could the compiler expect for p1.doSmth that it has an overriding method (while it doesn't know it's real type), while in p2.doSmth it just bound it?? am I missing something??

I'm sorry but this is really getting me headache ..

  • Wouldn't you get compilation error unless Child1 and Child2 extend Parent? – Zaki Anwar Hamdani Jan 03 '18 at 23:40
  • 1
    `Child1` doesn't extend anything other than `Object`, so `doSmth` doesn't override anything. Also, you're missing return types. Please post a [mcve] which reproduces your problem. – Andy Turner Jan 03 '18 at 23:41
  • @ZakiAnwarHamdani I meant to do so, I just edited it – Abd-Elrahman Adel Jan 03 '18 at 23:41
  • @AndyTurner sorry, it's a mistake, I just edited that – Abd-Elrahman Adel Jan 03 '18 at 23:43
  • Possible duplicate of [Static Vs. Dynamic Binding in Java](https://stackoverflow.com/questions/19017258/static-vs-dynamic-binding-in-java) – Zaki Anwar Hamdani Jan 03 '18 at 23:45
  • The method to be run is entirely determined at compile time. The compiler only knows about the existence of `doSmth(Object)`, because it only knows that `p1` and `p2` are instances of `Parent`, so that's the one that's invoked for both `p1` and `p2`. – Andy Turner Jan 03 '18 at 23:46
  • @AndyTurner No bro, for `p1.doSmth("String");` it's output is "Child1.doSmth" and this is called dynamic binding, my question is about `p2` – Abd-Elrahman Adel Jan 03 '18 at 23:50
  • @Abd-ElrahmanAdel what are you asking then? For `p2` it will invoke `Parent.doSmth(Object)`, because that's the only one it knows exists for a reference of `Parent` type; since it isn't overridden, it will print `Parent.doSmth`. – Andy Turner Jan 03 '18 at 23:53
  • In Java, the @Override makes no difference to the compilation results as methods with the same signature as on a parent automatically override Non-private and Non-static methods. – Dragonthoughts Jan 03 '18 at 23:53
  • @ZakiAnwarHamdani no my friend, I have already read that, and it has nothing to do with my question. @Dragonthoughts of course I know that, and the question has nothing to do with the override notation `@Override` – Abd-Elrahman Adel Jan 04 '18 at 00:04
  • @AndyTurner I want to know how the compiler knew that `doSmth` in `p2` is not overridden while it doesn't know it's real type yet?? – Abd-Elrahman Adel Jan 04 '18 at 00:06
  • In short: static binding happens at compilation time and is responsible for selecting *signature* (name and parameter types) of method to be invoked (based on *variable* type), dynamic binding happens at runtime and is responsible for finding *code* (body) of method (it is based on *actual type* of instance held by variable). So `p2.doSmth("String");` based on p2 type which is `Parent` picked `doSmth(Obhect)` method (since there is no better one in Parent type to handle String), and at runtime JVM checked Child2 to search for `doSmth(Object)`, didn't find it so it looked for it in ancestor. – Pshemo Jan 04 '18 at 00:08
  • @Abd-ElrahmanAdel I've got dog. I won't tell you what type of dog it is, but you know it has four legs, a tail and a wet nose. Maybe it's got short brown fur; maybe it's long and white. Doesn't matter; all you know it has legs, tail, nose. In the same way, you might not know that `p2` is a `Child2`, but you know it's a `Parent`, so you know for sure it's got the `doSmth(Object)` method. So that's the one which will be invoked. – Andy Turner Jan 04 '18 at 00:10
  • 3
    One issue here is the difference between over**loading** and over**riding**. `Child1` overrides `doSmth()` whereas `Child2` overloads it. – Code-Apprentice Jan 04 '18 at 00:14
  • 3
    *"I want to know how the compiler knew that doSmth in p2 is not overridden"* - It **doesn't** "know" that. In fact, all the compiler knows is that there will be *some* method with the signature `void doSmth(Object)`. The runtime (dynamic binding) will sort out which is used. But, in fact, it does know that `void doSmith(String)` does not override `void doSmith(Object)` ... because the method signatures are not override compatible. Overriding and overloading are different, and `void doSmith(String)` in `Child2` is an overload. – Stephen C Jan 04 '18 at 00:18
  • @StephenC Then you're saying this is going to be resolved in runtime which is dynamic binding. but I have read that static binding is that when the compiler binds the call with the body and it happens with overloading?? Or maybe you're saying that dynamic binding happened in this example because of polymorphism even if it is overloading?? – Abd-Elrahman Adel Jan 04 '18 at 00:29
  • 1
    The compiler decides whether the `p2.doSmth("String")` call matches a `doSmth(Object)` method or a `doSmth(String)` method . That is static binding. The runtime decides which `doSmth(Object)` method is called. That is dynamic binding. As you can see, your example involves both static and dynamic binding. Got it? – Stephen C Jan 04 '18 at 00:38
  • 1
    (The answers to your last questions are both Yes. There is no contradiction between those two propositions.) – Stephen C Jan 04 '18 at 00:41
  • Please also check the below stackoverflow thread also, https://stackoverflow.com/questions/19017258/static-vs-dynamic-binding-in-java – aparajith vangal Jan 04 '18 at 10:17
  • @StephenC thanks man, I know I had misconception, but yet I have doubts. I would be thankful if you answered this last question for me. Let's say there is a class called `Human` having `void talk()`, and the main method is in another class called `Test`, if we created an object of that class like this `Human h = new Human();` and called `talk()` like this `h.talk();`, did that use dynamic binding? – Abd-Elrahman Adel Jan 05 '18 at 17:44
  • 1
    Yes, it did. Conceptually speaking, static binding is used every time that there is a method call. Even if there is only one method, the compiler still goes through the same process of identifying and selecting it. Conceptually speaking, dynamic binding is used every time that there is an instance method call to a non-final method. The compiler doesn't know ahead of time if the method is going to be overridden. For example, by you declaring and using a subclass of `Human`. – Stephen C Jan 06 '18 at 00:35
  • Oh my god at least it's clear for me now, the problem is that I understood it incorrectly from the beginning. Thank you very very much, I appreciate it bro. – Abd-Elrahman Adel Jan 06 '18 at 00:50

1 Answers1

2

Trying to sum up discussion. Edit as required.

Static binding in Java occurs during Compile time while Dynamic binding occurs during Runtime.

At compile time, p1 and p2 both are types of Parent and Parent has doSmth(Object) method hence both lines binds to the same method.

    p1.doSmth("String");
    p2.doSmth("String");

During runtime, dynamic binding comes into picture.

p1 is instance of Child1 and Child1 has overridden doSmth(Object) hence the implementation from Child1 is used.

p2 is instance of Child2 and Child2 does NOT override doSmth(Object) hence the implementation of inherited method from Parent is called.