 How my Dog learned Polymorphism 
				What follows is an unedited transcript of a tutoring
						session between myself (CowGirl) and the ranch hound known as Clover. Clover's words are
						in blue. 
				So, Clover, let's review from our
					last lesson...  
				What do you get when you do this: 
				Dog d = new Dog(); 
				You get a new Dog
					object right? An instance of class Dog, referenced by a variable named "d".
					[tail wags] 
				Good Girl! Here's a treat... 
				So let's go beyond that. First, I'm
					going to show you a class inheritance tree for the example we're going to work on: 
				  
				This means: 
				Dog extends Animal  
						Animal is a superclass of Dog 
						Dog is a subclass of Animal 
						Dog inherits from Animal 
						Dog overrides the play() method 
						Dog adds one new method, bark() 
				Ruff!  
				Yes, very good. 
					So what happens now if I say: 
				Dog d = new Dog(); 
					d.play(); 
				[cocks head sideways]  
				Which play() method is called -- the one in Dog, or the one inherited
					from Animal? 
				Dog overrides the play() method, so you get the play()
					method in Dog. 
				Of course. That's what overriding means. The subclass object has
					"extended" the superclass by adding more specific functionality to the play()
					method.  
				OK, now what if I say... 
				Animal d = new Dog(); 
				 
				Is that code even legal? Will it compile? 
				Yes! Because Dog "is a" Animal. (or so you
					keep reminding me). Dog is a subclass of Animal, so I know that it's legal to have a
					reference type which is a superclass of the actual object type. Here, let me draw it [puts
					marker in mouth] 
				  
				  
				  
				Wow! I had no idea you could draw. And yes, that's correct. The
					reference type and the object type don't always match, but the rule is: 
				If the reference type is a class, the object it refers to MUST be
						either that same type or a subclass of that type. 
				If the reference type is an INTERFACE, the object it refers to MUST
						be an object from a class which implements the interface (either directly or through
					inheritance). 
				I understand how it works, but doesn't it
					"trick" a programmer into thinking that he (or she) has an Animal object when
					really a Dog object is hiding out there on the heap? 
				But what's the danger in that? A Dog can do ANYTHING an Animal can do
					(and more). So there's no harm. A programmer can safely call methods on the Animal
					reference, as though the object were really an Animal. The object is guaranteed to be able
					to respond to those method calls. 
				But let's get to the Big Question: 
				Animal d = new Dog(); 
					d.play();  
				Which play() is really called? The one in Animal, or the one in Dog? 
				Here's a hint: Java uses "late-binding" for instance methods. 
				Oh, well, that explains it... 
				Late-binding means Java doesn't "bind" (think: choose) a
					method call to an actual method at compile time. The choice of method happens later... at
					run-time. 
				Compile time = early, run-time = late. I get it. 
				Yes, exactly. 
				So Java waits to see what the ACTUAL object is... rather
					than using the reference type! Cool. [wags tail again] 
				You're really a smart dog, Clover. Despite what those sheep say. 
					And you're right.  
					Java does the right thing at run-time. 
					So if a Dog object is at the other end of an Animal reference, you still get the Dog
					version of the method. Always. It's not like this in C++, where a method has to marked
					"virtual" if you want to get this "polymorphic" behavior where the
					method is looked-up at run-time, LATE. 
				Based on the actual object's class, not the reference
					type. 
				But I still have another question... WHY would you want
					to do this? If you wanted the Dog to play (is now OK?) why not just use a Dog reference?
					Why use the Animal reference? 
				Referring to an object in many different ways (reference type is
					different from actual object class) is the point of polymorphism, which means "many
					forms". I can treat a Dog object like a Dog, or I can treat it like an Animal, or I
					can even treat it like a Pet, when I have the Dog class implement the Pet interface. 
				...and the reason for this would be... 
				Many reasons. Here's a good one... 
					You have a program that uses many different animal subclasses, and tells all the animals
					to play().  
				You could put all of the different animal subclass objects into an
					Animal [] array rather than keeping them in separate arrays for each subclass type. 
				Then you can loop through the Animal [] array and tell each element to
					play().  
				And the RIGHT play() method will be called for the REAL
					object at each slot in the array... am I right? 
				Yes! So the Compiler is... 
				.What, no treat? [doing that cute, sad, dog look] 
				Hang on and let me finish. So the Compiler is happy, since it knows that
					Animal has a play() method, it knows that each animal in the array can be safely treated
					like an Animal. 
				And if any element in the array happens to be a subclass of Animal, and
					it overrides the play() method, then a different play() method will be called for that
					element. 
				Late. The choice of the method is made "late". 
				At run-time. 
				So why not just use a generic collection like Vector?
					Can't you just put any object in there -- they don't even have to be from the same
					inheritance tree. 
				You've missed the point. A Vector would be less efficient, for one
					thing, and you'd have to cast the objects back to something more specific before you could
					call methods (other than, say, toString()). 
				What a pain. And that's not the main problem. 
				What if another programmer comes along after the guy who wrote the
					Animal program is gone? What if you don't even have his source code, but you need to add a
					new animal subclass like Cow? If all the different Animal subclasses had to be figured
					out, and cast, etc. then you could not add new Cow animals into the program without
					changing the original code. 
				But if the Animal program is simply expecting an array of Animals, then
					all I have to do is make my new Cow class a subclass of Animal, then it can be safely
					included in an Animal [] array and passed to a method in the Animal program. 
				So that's what you meant about extensibility with
					object-oriented programming... 
				Good girl! Yes -- that's part of what makes OOP so cool. OK, here's your
					treat. Now go write some code for me and I promise to keep the sheep away from your Duke
					chew toy. 
				[In Clover's next lesson, we'll be tackling AWT event-handling]  |