3

Given the following source and ouput:

Source:

public class A
{
  public void foo()
  {
    bar();
  }

  public void bar()
  {
    System.out.println ("in A's bar() method");
  }
}

public class B extends A
{
  @Override
  public void foo()
  {
    super.foo();

    // Do some specialized B stuff
  }

  @Override
  public void bar()
  {
    System.out.println ("in B's bar() method");
  }
}

public class Main
{
  public static void main (String... args)
  {
    B b = new B();

    b.foo();
  }
}

Output:

in B's bar() method

Can someone please explain to me how the JVM is smart enough to polymorphically call B's (as opposed to A's) bar() method in this situation? I'd like to know what kind of dynamic dispatch magic is going on behind the scenes here.

Update: In case I wasn't clear enough, I know basically WHAT is happening, I'm looking for specific details on HOW the JVM makes it happen under the hood. The answers so far are too simplistic.

Update 2: Maybe I wasn't clear enough. When b.foo() is called, then super.foo() is called, then bar() is called in class A's foo(). How does the bar() that is called when specifically invoking super.foo() not call class A's bar() method, since the super keyword explicitly specifies class A? What steps does the JVM have to go through to sort this out?

Also, does this mean it's a bad idea in general to call public methods from within their own class since they can be overridden in this way?

  • If you have the solution please share. I am also looking for the solution to this question. "What exactly going under the hood" – anuj pradhan Sep 05 '13 at 13:01

3 Answers3

3

Java uses the object's type when invoking the methods.

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

Let's say you used above code. Here what will happen is you are creating an object of type B and assign it to a reference of type A. Since the object type is B, you'll invoke the method in class B.

Gabe
  • 84,912
  • 12
  • 139
  • 238
  • I'm aware of the scenario you described, but that's not what I'm asking about. Thanks for the answer though. –  May 28 '13 at 07:11
1

Even if the constructor or method you're currently in is defined in a super-class, the object doesn't change type. It will still be an object of type B. This can be demonstrated by using the this keyword.

this refers to the current object. That is not the same as the class defining the current method or constructor.

Try typing the following into A's constructor or in the foo() method:

System.out.println(this.getClass());
Lone nebula
  • 4,768
  • 2
  • 16
  • 16
  • I did what you said; it's both interesting and helpful, but I'm still looking for a lot more details of what's going on under the hood. –  May 28 '13 at 07:17
1

The function call sequence is (from eclipse debug view):

1. B.foo()      // super.foo()
2. B(A).foo()   // bar()
3. B.bar()

After the thread calls super.foo(), the JVM will check if there's any implementation in B (since we still hold B.class in the stack), if there is, JVM will call it.

This feature is guaranteed by JVM implementation. It is not smart, it just be designed this way, just like C++'s virtual methods.

Hope it helps.

WoooHaaaa
  • 19,732
  • 32
  • 90
  • 138
  • Thanks for the explanation. I'd accept your answer if you went into a lot more detail about *how* exactly the JVM checks for an implementation in B, and walk through the steps the JVM takes in each method call of this program. Please see my updates. –  Oct 24 '13 at 11:08