2

I have a question about how this program selects the method.

Code(constructors aside):

class Father {
   int x;
   ..

   public int m(Father f) {
      return (f.x - this.x);
   }
}

class Son extends Father {
   int y;
   ...

   public int m(Father f) {
       return 100;
   }

   public int m(Son s) {
       return super.m(s) + (s.y - this.y);
   }
}

Main:

Father f1, f2; 
Son s1;
f1 = new Father(3);
f2 = new Son(3,10);
s1 = new Son(4,21);
System.out.println(f1.m(s1) + f2.m(s1)); 

I don't understand why f2.m(s1) prints 100. Personally I understood that if there are 2 methods with the same name, if there is an overload the choice is made with static types, and if override it's made with dynamic types;

f1.m(s1) searches dynamically a Father.m(Son) method, but it doesn't exist and Father.m(Father) is chosen instead

f2.m(s1) searches dynamically for a Son.m(Son) method, which exists and is an overload, so i think it should now prioritize static types and that searches for a Father.m(Son) method, which doesn't exist but the closest one is the Father.m(Father). Instead, the Son.m(Father) method is chosen: it is the method that is overloaded by the Son.m(Son) method okay, but it doesn't come out from the static search, so why it is chosen?

GameDroids
  • 5,584
  • 6
  • 40
  • 59
wattbatt
  • 447
  • 2
  • 13
  • 2
    Are you sure you are interpreting your results correctly? Maybe simplify all ur methods to just `return 1;`, `return 2;`, `return 3;`, or even better: add some `hello from ...` prints. To make sure its not your complex math there accidentally outputting the same number. – Zabuzard Oct 23 '19 at 09:57
  • this code is not mine, i am studying it. I am sure it prints 101 (1+100) I have the solution and also tested it. I want to see if my understanding is flawed – wattbatt Oct 23 '19 at 10:00
  • You will have to show the cosntructors here. – user207421 Oct 23 '19 at 10:23
  • Think about a `bark()` method in a `Dog` class. Now do `Animal a = new Dog();`. You can not call `a.bark()` although the actual instance is a `Dog`. The same happens here. the method that only exists in `Son` is not visible, it can not be called. After selecting the correct signature, Java will however consider the override of the method signature it wants to call. – Zabuzard Oct 23 '19 at 10:37

3 Answers3

2

f2 is declared as Father then instantiate by Son. The thing is in Father class the only m method is the one that accepts Father as input parameter. So when you instantiate f2 by Son class only the int m(Father f) is available for overriding. (as long as f2 is concern, there is not a int m(Son f) method) that's why f2.m(s1) returns 100.

Hadi Moloodi
  • 639
  • 7
  • 12
  • oh so you mean that if f2 is Son it does not "see" the Father.m(Father) method, it can only see the Son.m(Father) and it chooses it? – wattbatt Oct 23 '19 at 10:33
  • Yes, f2 declared as Father but instantiated as son so when you call f2.m(Father)(remember f2 is declared as Father so it only sees m(Father) ) what is really get called is Son.m(Father) because Son class overrides this method from Father. – Hadi Moloodi Oct 23 '19 at 10:37
2

f2 is a reference of type Father. Even though the object it references is a Son, the compiler still only allows using any methods that exist in Father when accessing a reference of that type. Therefore there is no other choice but using the method with signature int m(Father) (as it's the only one that exists in Father). Since Son has an override for this method, that override is executed.

f2.m(s1) searches dynamically for a Son.m(Son) method

That's where your error is rooted. It's not looking for a Son.m(Son) method, it's looking for a Father.m(Son) method and finds a Father.m(Father) method. Calling the override happens at a later point.

Max Vollmer
  • 8,412
  • 9
  • 28
  • 43
  • 1
    Very good explanation! I would go even further saying, it's not even *"looking"* for a `Father.m(Son)` method. `f2` is wearing the clothes of a `Father` and to the outside world it is just a `Father`, so it is the `Father.m(Father)` method that was called. But internally `f2` is still a `Son` and thus *acting* like a `Son` - and executing its own `m(Father)` override while silently accepting that the parameter is a `Son`. – GameDroids Oct 23 '19 at 11:14
1

Let's analyze one by one.

f2 = new Son(3,10);

As per concept Son object will be the binded at run time.

Then you called

f2.m(s1)

Now when it searches for m method in the Son object. It found that there are two of them 1. m(Father f) and 2. m(Son s).

But reference f2 was of type Father and only m(Father f) is common between Son and Father object hence m(Father f) of Son object will be selected at runt time for execution (in short m(Son s) will not be visible with Father as reference). That's why you are seeing that result.

You can debug the code too. It will show you the same execution flow.

ialam
  • 153
  • 1
  • 7