Java is an object-oriented programming language, so polymorphism in Java is the bread and butter of object-oriented programming in Java. In this tutorial we're going to find out what polymorphism is, why it is so useful, and then show how to use it to create elegant programs. This concept is somewhat difficult to put into practice because it happens to be much more abstract than many of the other concepts. However, if you can master it, you will become that much better of a programmer and you will have a much easier time mastering the Java language.
Polymorphism is THE concept to master if you want to master object-oriented programming. Because Java is an object-oriented language, it makes sense that you should learn the concepts and power of polymorphism in Java.
Simply put, polymorphism is what allows actions to act differently based on the object performing the action or the object the action is being performed on. Let's just use a super simple, real life example. What is a typical sound that a cat makes? Let's just say it's meow. Let's call this action makeSound() because remember, a method can represent an action. What sound does a dog make? Let's just say a dog goes woof. We can also call this action makeSound(). Let's also just pretend that all animals can makeSound(). Thus, makeSound(), depending on the type of animal, does something different. The action acts differently based on the object.
This concept of polymorphism in Java especially, is actually not hard to understand at all. Oh look, different animals make different sounds, and the same method can be used to make each distinct sound. If you've done the Java inheritance tutorial, you already know how to do this!
One powerful tool for using polymorphic behavior is to use the same method name but in the same class, over and over again to get the desired effects you want. How can we use polymorphism in Java to accomplish this?
Let's use our makeSound() example again. Let's say a dog makes a woof sound, but if the dog is injured, the dog might make a whimper noise instead. How can we use makeSound() to produce both sounds? Take a look at this code snippet:
NOTE: At this point, if you're not sure you understand the code you see, you REALLY should go back to the Intermediate Tutorials and read the tutorial on Methods In Java. Then you can come back to learn about polymorphism in Java once you have a better understanding of methods.
We can see here that depending on the number of parameters we pass to makeSound(), the dog will make a different sound. But wait! Couldn't we have just used an if statement and make this just one method? Yes, we could have done that and that's probably a better way of programming this for this particular example. What if an outside action causes the difference in dog sound though? Something like this:
If the dog did not have the variable to know it was hurt, you would not be able to write that if statement as easily.
You can overload a method as much as you want as long as the number of parameters are different or the types of parameters are different. You could not do this for example:
This is because those are the same number of parameters AND are the same types of parameters.
In Java, you can create a method in a superclass (or parent class), then in a subclass ALSO define that method. Let's see an example of this using Animal:
Now, let's say you could actually create Animals. If you could, then calling makeSound() would call the method defined in the superclass. If you create a specific Dog, calling makeSound() will display "woof". Now let's say you created a specific Cat. In that example, Cat does not have a makeSound() method, so when you call makeSound() on Cat, it calls the method in the superclass Animal and does nothing. Remember, Cat and Dog are subclasses of Animal because they extend Animal.
This behavior is called method overriding, and it is EXTREMELY powerful stuff when it comes to polymorphism in Java. Java will let you do this because its possible more specific types of objects have more specific behaviors for actions. How does Java then know which method to actually call? Java will always pick the object's true type for choosing which method to call, the superclass or the subclass. We will see what true type really means in the next section.
Do not let the long name confuse you. This is not that scary of a term! We won't discuss why this is dynamic, but let's just say that Java decides what method to call during runtime, or once the program is running. Dynamic method binding is how Java decides what method to call when it has to decide between the superclass and the subclass. So, how exactly does it decide? To illustrate this point, we must first illustrate the concept of true type versus referenced type.
Look, we just made a Dog but declared it as an Animal! Normally you would see this:
However, you can also declare a variable by its supertype or abstract type to make it more generic. Let's say you don't know what kind of animal you want:
Notice how the variable is not assigned to anything! We have an animal that has not been instantiate, and it does not equal anything. We can't create just Animals because they are abstract, so we must make a specific kind of animal, which is what we did with the example above by making the Animal be a new Dog.
So, which version of makeSound() would you use if you saw Animal animal = new Dog() ? Would you choose the Animal's version or the Dog's version? The answer is that Java will choose the true type, and the true type is the object that actually gets created. In this example, what we are really creating is a Dog, even though we are referencing the variable as an Animal.
Why in the world wouldn't we just do Dog dog = new Dog() ? The answer is that by using abstraction, you can actually group many different types of objects together. Let's see how we can use this concept for storing objects:
We could not do the above if the Cat objects and Dog objects were made the traditional way and not by referencing them as Animals.
It is very important you do not flip the reference and the true type! You could not do this:
First of all, in our example, you cannot create Animal objects because they are abstract. Let's assume you could though. This is still illegal because a specific type cannot be the reference of a more broad type. Think about it this way: A dog is an animal but an animal is not necessarily a dog. The above example is basically saying that an Animal is a Dog, and this is not always true.
Polymorphism in Java allows you to fully control how you group objects together and gives you the power to make them as specific as you want. It is also the crucial part of object-oriented programming that allows you to build hierarchies of objects, objects that have a logical structure that makes sense in the real world. Because of polymorphism, you can create highly sophisticated programs in Java that are easy to read and are well organized. It does not guarantee an awesome organization of your code, but if you're careful it can help you immensely in doing so.
My final advice about polymorphism in Java is to practice! Practice making a bunch of abstract and regular classes. Create your own object structures. Make different objects extend each other. Write the same methods over and over again using different parameters and putting them in the parent classes and subclasses. Then, test out your objects by writing a main class that uses the classes and methods you write in different ways. By doing so, you will be on your way to mastering this highly abstract, highly powerful concept!
If you would like to leave a comment for Polymorphism in Java, please click here to go to the questions/comments page! Or, simply click the appropriate contact link in the sidebar. Thanks!