Java for Humans {Polymorphism}

Lincoln W Daniel
Jan 20, 2016 · 6 min read
View Table of Contents | Download Supporting Code | Subscribe to ModernNerd Youtube Channel for Coding Videos | By Lincoln W Daniel

In our short look at polymorphism at work in both the Class Inheritance and Abstract Classes & Interfaces chapters, we got a glimpse at how powerful polymorphism is. In both chapters, we learned that any object that can pass more than one is-a test, that is any object that is of more than one type, is considered polymorphic. With that said, we can define polymorphism as the ability of an object to take on more than one form.

Why is Polymorphism Important & Useful

Polymorphism is one of the most important concepts in object oriented programming. It is what allows us to say that all types in Java are the type of its class as well as the type of the Object class; we’ve learned that all objects in Java are instances of the Object class because of Java’s class hierarchy.

One Functionality for All

We learned in the Class Inheritance chapter that If we can say an instance of a class can be of more than one type, we can build functionality for one class that works for any class that extends it. We created a Human class that our Warrior, Archer, and FireArcher all inherited from. That allowed us to create methods that accepted them all as parameters because we could group them all as being Human. That is polymorphism at work.

One Collection for All

Remember in the three Data Structures chapters that with any data structure, collection, we can only store elements of the same type: each element of a String array must be of type String and each element in a Human LinkedList must be of type Human. In the HashMaps chapter, we saw that if we don’t explicitly specify the type of our keys and values, Java implicitly sets the map to store keys of type Object and values also of type Object because every class in Java extends the Object class provided by Java. This is only legal because of polymorphism. Let’s revisit our Conquer game example from earlier to see how we can collect all our friends in the game in a single list.

The classes of the different characters in the game will be omitted from this chapter, so make sure to open the supporting source code.

Remember that we have a Character interface that every character class implements, an abstract Human class that all human character class extends, and an abstract Pet class that all pet classes extend. We will focus on the Human class and its subclasses because while a user can have a pet, a user who plays our game can only be a human character. Let’s create a Human instance for ourself, currentUser, and a couple Human instances to represent other users:

//the Human character representing the current user
Human currentUser = new Archer("ModernNerd");

//other Human characters playing the game
Archer human2 = new Archer("Tom");
Human human3 = new FireArcher("Christina");
Warrior human4 = new Warrior("Tyrone");
Taoist human5 = new Taoist("Jerome");

We are the currentUser Human instance which is also an Archer instance. Notice that human3 is like our character: its of type Human but is instantiated as a FireArcher. Again, that’s the beauty of polymorphism. Let’s take a look at the Human class:

public abstract class Human implements Character {
private LinkedList<Human> friendsList = new LinkedList<>();
...

public LinkedList<Human> getFriends() {
return friendsList;
}
...
}

It has a LinkedList, friendsList, that accepts Human instances as elements. We will use this to hold our list of friends. Let’s get it and store a reference to it in a local variable and add the other characters to it because they are our friends:

/*store a reference to current user's 
friend list in a local variable*/
LinkedList<Human> currentUserFriendsList = currentUser.getFriendsList();
//add other user's to current user's friend list
currentUserFriendsList.add(human2);
currentUserFriendsList.add(human3);
currentUserFriendsList.add(human4);
currentUserFriendsList.add(human5);
System.out.printf("Current user has %d friends.", currentUser.getFriendsList().size());
//prints "Current user has 4 friends."

Now we have four friends in our list. Remembered that each element in our list is stored as a Human instance, so if we want to retrieve a friend from the list, it will be returned as a Human. Let’s retrieve human2, “Tom”, which is also an Archer:

Human ourFriendTomTheHuman = currentUserFriendsList.get(0);if(ourFriendTom instanceof Archer) {
System.out.println("\nOur friend Tom is an instance of the Archer class");
Archer ourFriendTomTheArcher = (Archer) ourFriendTomTheHuman; System.out.println("Tom can find more arrows for battle.");
ourFriendTomTheArcher.findArrows();
} else {
System.out.println("\nOur friend Tom is NOT an instance of the Archer class");
//ourFriendTom.findArrows(); doesn't work
System.out.println("Tom cannot go find arrows because he is not an Archer");
ourFriendTomTheHuman.attack(currentUser);
}
/*Prints:
Our friend Tom is an instance of the Archer class
Tom: Found 5 arrows!
Tom: I now have 8 arrows.
*/

There’s a couple new things happening in that code snippet, so let’s walk through it line by line. In the first line, we call the get() instance method on our LinkedList holding our friends and get the first element which is at index zero (0). This is Tom who we know was an archer before we added him to the list. However, he was returned to us as a Human, so we call him ourFriendTomTheHuman for now.

Type Casting

If we want to turn Tom back into an Archer, we must cast him to one. Type casting in Java is the act of casting, or converting, one type, a class or interface, into another type. As usual, we should check to make sure Tom is actually an Archer disguised as a Human before we try to cast him back to an Archer. We do the check in the next line of code by using the instanceof operator in an if-then statement. The instanceof operator returns true if the object on the left is an instance of the class on the right, and it returns false otherwise. In this case, it returns true because Tom is indeed an instance of the Archer class as we already knew. Now we are inside the first block of the if-then statement.

After printing that Tom is an instance of the Archer class, on the next line, we cast the ourFriendTomTheHuman object to an Archer and save this new copy of Tom to a new Archer variable called ourFriendTomTheArcher. As you can see, to type cast an object, we simply put the class of type we want to cast our object to inside of a set of opening and closing parenthesis to the left of the variable holding the object.

You can type cast primitive values like ints and doubles, too. Do some more research on type casting because it is a handy tool.

Now that we have converted Tom from being a Human back to an Archer, we can call its findArrows() instance method so it can find more arrows to use in battle. If we had not converted Tom back to an Archer, he could not call the findArrows() instance method because he would not be of type Archer. However, Tom could always call the attack() instance method of Human because all Human instances have an attack method. This is where it gets a little tricky, so stick with me:

ourFriendTomTheHuman.attack(human3);
/*Prints:
Tom: Attacking Christina with my arrows!
Christina: I've been hit. My health now = 99.0
*/

Because Tom was instantiated as an Archer before being added to our LinkedList of Human objects, he still has access to the abstract Human methods that were already implemented by the Archer class and made available to Tom when he was instantiated. With that said, if we make ourFriendTomTheHuman attack human3, “Christina”, he still attacks with his arrows. The only problem here is, because ourFriendTomTheHuman would not be able to find arrows after he uses it all, his attack() method will be useless at that point. That is why we should cast him back to an Archer.

By now, I hope you understand why polymorphism is so special to object oriented programming. Moving forward, be sure to employ polymorphism in your Java programming career. Take a look at the supporting source code and change things around to practice more.


HackerNoon.com

how hackers start their afternoons.

Lincoln W Daniel

Written by

My passion is in developing software to enable people to accomplish their goals more efficiently. Author @JavaForHumans.com. Creator of @Smedian.com

HackerNoon.com

how hackers start their afternoons.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade