Reputation: 4671
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
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
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
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
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
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
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