The next principle of Object-Oriented programming that we'll learn about is polymorphism.
Polymorphism
Polymorphism is the ability to take multiple forms. Specifically, in object-oriented programming, polymorphism is where a subclass can define their own unique behaviors, and yet share some of the same behaviors of their superclass.
An example of polymorphism is where an object has a superclass type but is an instance of a subclass.
Here we have an object called dog
and it's defined as type Animal
but it is an instance of Dog
.
We're able to do this because Dog
inherits from Animal
, and therefore dog
is a Animal
.
Let's demonstrate an example of polymorphism between an Animal
, Dog
, and Cat
.
I've created a new class called Animal
.
In this class, let's just make a simple method called makeSound()
and it'll just print out a generic message.
package chapter10;
public class Animal {
public void makeSound(){
System.out.println("unknown animal sound");
}
}
Now I'm going to go into this Dog
class, which is also new, and we're going to inherit from the Animal
class.
And inside of here we're going to override that makeSound()
method and we'll print something that's specific to the Dog
.
In addition to the makeSound()
method that we've inherited, let's also add a new method in here's that specific to the Dog
called fetch()
.
package chapter10;
public class Dog extends Animal {
@Override
public void makeSound(){
System.out.println("woof");
}
public void fetch(){
System.out.println("fetch is fun!");
}
}
Okay.
Now let's go into the Cat
class.
This will also inherit from Animal
and will override the makeSound()
method, and then add its own method.
package chapter10;
public class Cat extends Animal {
@Override
public void makeSound(){
System.out.println("meow");
}
public void scratch(){
System.out.println("I am a cat. I scratch things.");
}
}
Okay, now for demonstrating polymorphism.
Let's go into this new class called Zoo
and we'll make a main
method. Let's go ahead and create a normal Dog
object for now.
package chapter10;
public class Zoo {
public static void main(String[] args){
Dog rocky = new Dog();
}
}
Now this dog Rocky, he should be able to fetch because the fetch()
method is inside of Dog
. And then rocky
should also be able to make a sound, right?
public static void main(String[] args){
Dog rocky = new Dog();
rocky.fetch();
rocky.makeSound();
}
And since we overrode the makeSound()
method in the Dog
class, that's the one that will be executed.
Let's try it.
Yep, “fetch is fun!” and the makeSound()
is the one from the Dog
class, not the Animal
class. So that's just normal.
Now I want to show you about the polymorphism part.
I can specify this type as Animal
, and let's call this dog sasha
. And I'm going to instantiate sasha
as a Dog
.
Animal sasha = new Dog();
sasha.makeSound();
So, sasha
is of type Animal
but an instance of Dog
. Now when I do this, sasha
can make a sound even though sasha
is of type Animal
, because we overrode this makeSound()
method in the Dog
class. So, that is the one that will be executed.
When we run this, we get “woof”, so, we see that it was the overridden method.
Let's continue on, we're going to actually change Sasha's type — this is real polymorphism.
Animal sasha = new Dog();
sasha.makeSound();
sasha = new Cat();
sasha.makeSound();
I can say sasha
now is a Cat
. So, I've changed Sasha from an instance of Dog
to an instance of Cat
.
Why is this legal?
Because they are both of type Animal
, and since I've specified sasha
as type Animal
, then this is legal. So now we can make a sound. And now we should see two different sounds.
Yep. woof and meow.
Now, because sasha
is of type Animal
and not of type Cat
, then sasha
does not have access to the scratch()
method. Because the scratch()
method belongs to Cat
, and yet sasha
is of type Animal
so we cannot make a direct call of sasha.scratch()
.
However, we can still get around this by casting.
Type Casting
Casting is the act of converting an object’s type into a different type.
If we did sasha.scratch()
, notice here Sasha has been cast to type Cat
.
Animal sasha = new Dog();
sasha.makeSound();
sasha = new Cat();
sasha.makeSound();
((Cat) sasha).scratch();
So, this is not changing the overall object — sasha
is still of type Animal
. But it's saying in this specific call go ahead and make sasha
of type Cat
, just so that we can execute this method.
And that worked as expected.
Now let's create a new method inside of this Zoo
class to feed the animals.
public static void feed(Animal animal){
}
Now notice that this method feed()
takes an Animal
.
Technically rocky
is a Dog
, but yet we could still pass rocky
into this feed()
method.
Dog rocky = new Dog();
rocky.fetch();
rocky.makeSound();
feed(rocky);
The reason we're able to do that again is because of polymorphism. Because it accepts this superclass of Animal
, that means we can pass in an Animal
object or any subclass of Animal
.
Let's do the same for sasha
.
Animal sasha = new Dog();
sasha.makeSound();
feed(sasha);
Now within this method of feed()
, let's say that I want to do different things based on the type. If it's actually a dog, I might want to give it dog food, and if it's a cat I want to give it cat food.
Even though our parameter is of type Animal
, there's a way that we can still figure out exactly what the subclass is by doing a check.
I can use an operator that's called instanceof
.
if(animal instanceof Dog){
}
instanceof Operator
instanceof
will do a check to see if whatever's on the left side is actually an instance of whatever you specify on the right side.
So, I can check to see if this Animal
is an instance of Dog
. And this will return a boolean value. If true, then I know that this object was instantiated as type Dog
.
Likewise, we can check for Cat
.
if(animal instanceof Dog){
System.out.println("here's your dog food");
}
else if(animal instanceof Cat){
System.out.println("here's your cat food");
}
Okay, let's run it now and see what happens.
package chapter10;
public class Zoo {
public static void main(String[] args){
Dog rocky = new Dog();
rocky.fetch();
rocky.makeSound();
feed(rocky);
Animal sasha = new Dog();
sasha.makeSound();
feed(sasha);
sasha = new Cat();
sasha.makeSound();
((Cat) sasha).scratch();
feed(sasha);
}
public static void feed(Animal animal){
if(animal instanceof Dog){
System.out.println("here's your dog food");
}
else if(animal instanceof Cat){
System.out.println("here's your cat food");
}
}
}
Output:
fetch is fun!
woof
here's your dog food
woof
here's your dog food
meow
I am a cat. I scratch things.
here's your cat food
We see that the first call was to fetch()
, and we got “fetch is fun” from the Dog
class.
“woof” is from the overwritten makeSound
method of the Dog
class.
When passing rocky
to feed()
, we see that it did find that this was an instance of Dog
.
For sasha
who's of type Animal
but an instance of Dog
, we also see the makeSound()
prints “woof”
It also feeds sasha
dog food when we did the instanceof
check.
When sasha
became a cat, the makeSound
prints “meow”.
Then we called the scratch()
.
This — “here’s your cat food” — was printed out because instanceof
shows that it is a Cat
.
Here are the key points about polymorphism.
instanceof
operator is used to determine if an object is an instance of a certain class.For your optional assignment for this chapter, create a class called Fruit
.
This class should contain a field called calories
and a method called makeJuice()
, which prints a statement — something like “juice is made” - just something generic.
Then create two subclasses of the Fruit
class. For example, you can do Apple
and Banana
, or Orange
and Lemon
, whatever you would like to do.
And then create methods within these classes that are specific to them. So, if you're going to do the Apple
class, then do something like removeSeeds()
. If you're going to do the Banana
class, then do something like peel()
.
And then set the calories
within the constructors of these subclasses.
Override the makeJuice()
method to print the specific type of juice that's going to be made.
And then finally create a Market
class which tests polymorphism by creating several variations of these objects.
Good luck.
Solution
Programming can be done many different ways, but here’s my solution.