• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Polymorphism

 
B Gallagher
Greenhorn
Posts: 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
OK, I am a little confused about polymorphism. Can someone explain to me what's going on here?
Given:

This gives me "Horse eating hay ":

But this does not compile:

So in the first case, "the compiler looks at the actual object type to determine which method is invoked", but in the second case, it (apparently) does not. Why? Is it because in both cases I am declaring an Animal reference, and the eat method that takes a string is not in that class? If so, then the phrase "the compiler looks at the actual object type" seems a bit misleading to me, because in both cases it is actually looking at the reference type.
Edited by Corey McGlone: Added CODE Tags
[ March 31, 2004: Message edited by: Corey McGlone ]
 
Charlie Goth
Ranch Hand
Posts: 60
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Animal ah2 = new Horse();
ah2.eat("Carrots");
This doesn't work because there is no method eat(String s) in Animal, it only works on references of type Horse. There is an eat() method though (in Animal) so that works fine.
Charlie
 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, I see where you're getting confused. First of all, realize that the compiler can't look at the type of object that a variable references - it doesn't know because that isn't determined until run-time.
We have the notion of compile-time types and run-time types. A compile-time type is the type we have declared for a variable. In your example, ah and ah2 both have compile-time types of Animal. A run-time type is the type of an object that a variable references at a given point in time during execution. In your example, ah and ah2 both have run-time types of Horse.
So, what does this all mean?
Well, the compiler can only check one type - you guessed it, the compile-time type. Therefore, the compiler knows that ah and ah2 reference some type of Animal. That might be an Animal and it might be a Horse, but the compiler doesn't know for sure.
As the compiler doesn't know what it really references, it has to err on the side of caution. ah.eat() works just fine because Animal has an eat() method that takes no arguments. Therefore, the compiler knows that this method invocation has a valid target (it might be overridden, but the compiler doesn't know and doesn't care - all it cares about is the existence of a valid method to invoke).
When you invoke ah2.eat("Carrots"), however, the compiler is put in quite a bind. The compiler knows that ah2 has a compile-time type of Animal. That means that it can reference an Animal or any subclass on Animal. However, Animal doesn't have a method named eat that takes a String as a parameter. If the run-time type were to be Horse (which, in this case, it is), the method invocation would work fine. But, like I said earlier, the compiler knows nothing about what ah2's run-time is. Because the compiler knows that ah2 might reference an Animal object, it's possible that there will be no valid method to invoke. That's a big no-no for the compiler, so it complains.
I hope that helps,
Corey
 
B Gallagher
Greenhorn
Posts: 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So -- if I understand correctly -- adding a new eat(String) method to the Animal class would allow that code to compile, but it would *run* the eat(String) method from Horse!
 
Ray Stojonic
Ranch Hand
Posts: 326
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The compiler does indeed look at the reference type, which is why Animal.eat( String ) won't compile.
The the proper method is called on the appropriate object during runtime via dynamic method lookup, ie:
Animal a = new Horse();
a.eat();
o/p : Horse eating hay
During compilation, the compiler says "okay, call eat() on this Animal object"
During runtime, the JVM says "hey, this is a Horse, call Horse.eat()", which is the cool part of polymorphism.
You'll have to fill in the missing parts in this example, but here it is:

o/p:
Horse eating hay
Chicken eating feed
Pig eating apples
 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by B Gallagher:
So -- if I understand correctly -- adding a new eat(String) method to the Animal class would allow that code to compile, but it would *run* the eat(String) method from Horse!

Absolutely!
 
Brian Albin
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One quick question ...

I can understand upcasting the reference to an Animal when storing objects of type Horse, Chicken, Pig in an array.
Animal[ ] = new { ... };
One array can hold various types of animals.

But what advantage is their in saying ...
Animal ah = new Horse( );
It would seem that ...
Horse ah = new Horse( );
is a better description of what is actually taking place in code.
Brian Albin
 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Brian Albin:
But what advantage is their in saying ...
Animal ah = new Horse( );
It would seem that ...
Horse ah = new Horse( );
is a better description of what is actually taking place in code.

You're right, Brian. It would seem better to have the compile-time type be Horse, in this case. However, this is a somewhat contrived example derived to show the function of polymorphism. In real life, ploymorphism really shines when we don't know, ahead of time, what type of object we're really dealing with.
Corey
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic