OO Programming Tutorial - Part 4, Polymorphism, November 2002
Polymorphism is one of those topics that just drives beginning programmers nuts. I'm going to try to break this down to where just about anyone can understand it and
hopefully break through some of the smoke and mirrors. Basically the term means many forms
, in your programs it mean your objects don't have to always be what they are originally
declared as.....Huh? OK, let's back up the bus just a bit. We know our Dog is a Dog, right? But isn't our Dog also an Animal? Wasn't our superclass Animal created to handle all the
nonsense that all of our subclasses would have instead of recoding it in every class? Ah, I see a glimmer of light there.
Before we go any further I want to create one more subclass to help with the explanation of this so here is our
Elephant class. OK, so now we have two very different creatures (objects) that are both Animals.
Now since we have several objects that are, in fact, Animals we can write code like this:
Animal anim = new Dog();
or:
Animal anim2 = new Elephant();
Now when you call anim.sleep() or anim2.sleep you get the methods in the subclass. Say What? OK, we probably need to back up one more time. Our Dog & Elephant objects ARE Animals.. we have already agreed on that. We can create them as above due to the fact that these objects can do everything an Animal can do and more. There is no danger here and the compiler knows this. This is handled by the JVM due to what's known as "late binding". The JVM basically waits until run time so it knows what type of object it is dealing with, in the first case a Dog, the second an Elephant. When you override a method, like we have in our two subclasses, the JVM looks at the object on the right side of the assignment for the method. Had we not overridden the method then once again the JVM would look in the subclass, not find the method and then look to the superclass, just like normal inheritance would work. So why in heaven's name would we want to do this in the first place? What if we wanted to create instances of all of our subclasses and call their methods. Sure we could do this line by line but it gets just a touch monotonous. Instead we could do this:
Animal [] zoo = new Animal[4];
zoo [0] = new Dog(20, 35, 7, true, "hound", "Duke");
zoo [1] = new Elephant(144, 2000, 40, true, 10, "African");
zoo [2] = new Dog(10, 9, 6, false, "miniature", "Lola");
zoo [3] = new Elephant(244, 4000, 50, false, 15, "Indian");
for (int i = 0; i < zoo.length ; i++) {
zoo[i].sleep(32);
}
This code will compile & run without a single problem. We are able to call our sleep method from ALL of our classes without going through tons of lines of code and we know the correct sleep method (the one from the subclasses) will be called. Pretty neat huh? This type of code creates a myriad of possibilities when the need to manipulate multiple subclasses is required and also allows you to create objects on the fly, pass them around in an array and then access the objects without having to worry about exactly what object they are. This could be done in a Vector but remember that a Vector returns a generic object and you would have to test each object and cast them back into their proper form....this is much easier!
Now there is one other thing that really messes up programmers when attempting this type of code the first time, overriding variables.....which one is called? We are going to add a couple of more lines of code to the above example to show what happens here.
Animal [] zoo = new Animal[4];
zoo [0] = new Dog(20, 35, 7, true, "hound", "Duke");
zoo [1] = new Elephant(144, 2000, 40, true, 10, "African");
zoo [2] = new Dog(10, 9, 6, false, "miniature", "Lola");
zoo [3] = new Elephant(244, 4000, 50, false, 15, "Indian");
for (int i = 0; i < zoo.length ; i++) {
zoo[i].sleep(5);
if (zoo[i] instanceof Elephant) {
zoo[i].setHeight(20);
System.out.println(zoo[i].height);
}
}
I've also changed the access modifier in our Animal class for our height variable (you'll see why in a second) & I've created a height variable in our Elephant class, along with a setHeight method. Now if you look at the code above you will see that we are testing our objects in the loop to see if they are an instance of Elephant. If it is we are using the setHeight method to change the height of the Elephant to 20 (Little bugger). Then we are checking the new height to make sure it was set to the new variable.....and guess what? It's not! The program returns 144 & 244......Why you say? Because when you create an object as we have:
Animal anim = new Elephant(244, 4000, 50, false, 15, "Indian");
and then call a variable (even if it's overridden in the subclass) the variable you get back will be from the superclass. I know it's confusing at first but once you learn the rules it's a smooth sail. Just remember variables come from the left side of the object's creation statement (the superclass), the methods come from the right (provided the subclass has overridden the method).
Well I know I could use a break about now and I'm sure you can so let's break here and when your head stops pounding come back & venture on to the next page.
Lissa Lee, bathandbodycare.com | More Testimonials >>