Thirumalai Parthasarathi
Thirumalai Parthasarathi

Reputation: 4671

Why is the super class method called?

class One { 
  public void doThing(One o) {System.out.println("One");}
}

class Two extends One{
  public void doThing(Two t) {System.out.println("Two");}
}

public class Ugly {
  public static void main(String[] args) {
    Two t = new Two();
    One o = t;
    o.doThing(new Two());
  }
}

Result : One

class One { 
  public void doThing(One o) {System.out.println("One");}
}

class Two extends One{
  public void doThing(Two t) {System.out.println("Two");}
}

public class Ugly {
  public static void main(String[] args) {
    Two t = new Two();
    One o = t;
    t.doThing(new Two());
  }
}

Result : Two

I know that at runtime, even though the object reference is of the super class type, the actual object type will be known and the actual object's method will be called. But if that is the case, then on runtime the doThing(Two t) method should be called but instead the super class method doThing(One o) is called. I would be glad if somebody explained it

In the second piece of code it prints "Two".

Question : when calling from the super class reference it is calling the doThing(One o) when calling from the sub class reference it is calling the doThing(Two o)

NOTE: I know that i am over loading and not over riding. i have edited my question for better clarity.

Upvotes: 10

Views: 438

Answers (6)

Adam Burley
Adam Burley

Reputation: 6079

Because One does not have a method doThing(Two t), the statement o.doThing(new Two()) will never be resolved to doThing(Two t). Just like if you added a method doAnotherThing() to Two, you couldn't call o.doAnotherThing() - this would be a compiler error. Even though new Two() is of both type Two and One, o.doThing(new Two()) is always going to call the method doThing(One o) for this reason. Since you did not override this method in Two, it's calling the version from class One.

However, if you added public void doThing(One o){System.out.println("Three");} to class Two, you would find o.doThing(new Two()) did print Three at runtime. This is because it's still calling doThing(One o) but at runtime it will use the overridden method from the class Two (runtime type of o).

Upvotes: 0

Thirumalai Parthasarathi
Thirumalai Parthasarathi

Reputation: 4671

At the compile time the compiler searches the class One for the method doThing(Two t) but since there isn't a method with that signature it starts widening its search and finds doThing(One o). Then it holds the binary file with the descriptor one parameter whose type is One : void. At runtime since the object invoking the method is of type Two, in class Two it looks for the method that matches the descriptor and doesn't search for the method doThing that accepts an object of Two as it considers the descriptor in the binary file it links the call to the method doThing(One o).

the java specs was of great help explaining this. here is the link

Upvotes: -1

Ahmad
Ahmad

Reputation: 13

This is something trick question
Your statment
One o = t;
I think , you are assuming that class One 'o' is equal to Class Two 't', which is not actually equal to class Two 't'
as Class Two 't' is inherited from Class One, so it will assign the base class One in your case,
So variable 't' is reference of the class One and hence will call the method of class One.
More over you create one more class named as ClassC class and try to set your statement
ClassC c= new ClassC ()
and then
One o = c;
You will get an error... hope the answer your question.

Upvotes: 0

user1368271
user1368271

Reputation:

You are just overloading,as you said

    Two t = new Two();
    One o = t;
    o.doThing(new Two());

Even though the actual object at runtime is a Two object and not a One object, the choice of which overloaded method to call (in other words, the signature of the method) is NOT dynamically decided at runtime. Just remember, the reference type (not the object type) determines which overloaded method is invoked!

When you call doThing() method with Two object argument,you will invoke One super class doThing() method.The doThing() method needs a One object, and Two IS-A One. So, in this case, the compiler widens the Two reference to a One object, and the invocation succeeds. The key point here is that reference widening depends on inheritance, in other words the IS-A test.

Upvotes: 1

TheKojuEffect
TheKojuEffect

Reputation: 21101

The method doThing() have different method signature in One and Two.

One.doThing(One one)
Two.doThing(Two two)

Since, the signature isn't matched, Two.doThing(Two) doesn't Override One.doThing(One) and since o is of type One, One.doThing() is called.

Also to be noted that One.doThing(One) can take instance of Two as an argument for One.doThing(One) as Two extends One.

Basically, "@nachokk - You are Overloading, not Overriding"

In first scenario, when you did

Two t = new Two();
One o = t;
o.doThing(new Two());

So, o is an instance of One and Two.doThing(Two) isn't available to o thus calls One.doThing(One)

In second scenario,

Two t = new Two();
One o = t;
t.doThing(new Two());

t is an instance of Two and thus Two.doThing(Two) is called.

Upvotes: 13

Matej
Matej

Reputation: 9058

The excelent book SCJP for Java 6 states:

If a method is overridden but you use a polymorphic (supertype) reference to refer to the subtype object with the overriding method, the compiler assumes you’re calling the supertype version of the method.

So basically with using supertype for reference you're telling compiler to use supertype method.

Upvotes: 1

Related Questions