Polymorphism—or an object’s skill to execute specialised actions based mostly on its kind—is what makes Java code versatile. Many design patterns created by the Gang Of 4 depend on some type of polymorphism, together with the Command sample. On this article, you’ll be taught the fundamentals of Java polymorphism and easy methods to use it in your applications.
Issues to find out about Java polymorphism
- Polymorphism and Java inheritance
- Why polymorphism is essential
- Polymorphism in technique overriding
- Polymorphism with the core Java courses
- Polymorphic technique calls and casting
- Reserved key phrases and polymorphism
- Frequent errors with polymorphism
- What to recollect about polymorphism
Polymorphism and Java inheritance
We’ll deal with the connection between polymorphism and Java inheritance. The principle factor to bear in mind is that polymorphism requires an inheritance or an interface implementation. You possibly can see this within the instance under, that includes Duke and Juggy:
public summary class JavaMascot {
public summary void executeAction();
}
public class Duke extends JavaMascot {
@Override
public void executeAction() {
System.out.println("Punch!");
}
}
public class Juggy extends JavaMascot {
@Override
public void executeAction() {
System.out.println("Fly!");
}
}
public class JavaMascotTest {
public static void foremost(String... args) {
JavaMascot dukeMascot = new Duke();
JavaMascot juggyMascot = new Juggy();
dukeMascot.executeAction();
juggyMascot.executeAction();
}
}
The output from this code will likely be:
Punch!
Fly!
Due to their particular implementations, each Duke
‘s and Juggy
’s actions will likely be executed.
Why polymorphism is essential
The aim of utilizing polymorphism is to decouple the shopper class from the implementation code. As an alternative of being hard-coded, the shopper class receives the implementation to execute the mandatory motion. On this approach, the shopper class is aware of simply sufficient to execute its actions, which is an instance of free coupling.
To higher perceive some great benefits of polymorphism, Â check out the SweetCreator
:
public summary class SweetProducer {
public summary void produceSweet();
}
public class CakeProducer extends SweetProducer {
@Override
public void produceSweet() {
System.out.println("Cake produced");
}
}
public class ChocolateProducer extends SweetProducer {
@Override
public void produceSweet() {
System.out.println("Chocolate produced");
}
}
public class CookieProducer extends SweetProducer {
@Override
public void produceSweet() {
System.out.println("Cookie produced");
}
}
public class SweetCreator {
non-public Record<SweetProducer> sweetProducer;
public SweetCreator(Record<SweetProducer> sweetProducer) {
this.sweetProducer = sweetProducer;
}
public void createSweets() {
sweetProducer.forEach(candy -> candy.produceSweet());
}
}
public class SweetCreatorTest {
public static void foremost(String... args) {
SweetCreator sweetCreator = new SweetCreator(Arrays.asList(new CakeProducer(),
new ChocolateProducer(), new CookieProducer()));
sweetCreator.createSweets();
}
}
On this instance, you possibly can see that the SweetCreator
class solely is aware of the SweetProducer
class. It doesn’t know the implementation of every Candy
. That separation provides us the pliability to replace and reuse our courses, and it makes the code a lot simpler to take care of. When designing your code, all the time search for methods to make it as versatile and maintainable as doable. Polymorphism is a really highly effective method for writing reusable Java code.
Tip: The @Override
annotation obligates the programmer to make use of the identical technique signature that should be overridden. If the strategy isn’t overridden, there will likely be a compilation error.
Is technique overloading polymorphism?
Many programmers are confused concerning the relationship of polymorphism to technique overriding and technique overloading. Solely technique overriding is true polymorphism, nonetheless. Overloading shares the identical technique’s title however the parameters are completely different. Polymorphism is a broad time period, so there’ll all the time be discussions about this subject,
Polymorphism in technique overriding
It’s doable to vary the return kind of an overridden technique if it’s a covariant kind. A covariant kind is basically a subclass of the return kind. Here is an instance:
public summary class JavaMascot {
summary JavaMascot getMascot();
}
public class Duke extends JavaMascot {
@Override
Duke getMascot() {
return new Duke();
}
}
As a result of Duke
is a JavaMascot
, we will change the return kind when overriding.
Polymorphism with the core Java courses
We use polymorphism on a regular basis within the core Java courses. One quite simple instance is once we instantiate the ArrayList
class declaring the  Record
interface as a sort:
Record<String> checklist = new ArrayList<>();
To go additional, think about this code pattern utilizing the Java Collections API with out polymorphism:
public class ListActionWithoutPolymorphism {
// Instance with out polymorphism
void executeVectorActions(Vector<Object> vector) {/* Code repetition right here*/}
void executeArrayListActions(ArrayList<Object> arrayList) {/*Code repetition right here*/}
void executeLinkedListActions(LinkedList<Object> linkedList) {/* Code repetition right here*/}
void executeCopyOnWriteArrayListActions(CopyOnWriteArrayList<Object> copyOnWriteArrayList)
{ /* Code repetition right here*/}
}
public class ListActionInvokerWithoutPolymorphism {
listAction.executeVectorActions(new Vector<>());
listAction.executeArrayListActions(new ArrayList<>());
listAction.executeLinkedListActions(new LinkedList<>());
listAction.executeCopyOnWriteArrayListActions(new CopyOnWriteArrayList<>());
}
That is ugly code, isn’t it? Think about attempting to take care of it! Now take a look at the identical instance with polymorphism:
public static void foremost(String … polymorphism) {
ListAction listAction = new ListAction();
listAction.executeListActions();
}
public class ListAction {
void executeListActions(Record<Object> checklist) {
// Execute actions with completely different lists
}
}
public class ListActionInvoker {
public static void foremost(String... masterPolymorphism) {
ListAction listAction = new ListAction();
listAction.executeListActions(new Vector<>());
listAction.executeListActions(new ArrayList<>());
listAction.executeListActions(new LinkedList<>());
listAction.executeListActions(new CopyOnWriteArrayList<>());
}
}
The advantages of polymorphism are flexibility and extensibility. As an alternative of making a number of completely different strategies, we will declare only one technique that receives the generic Record
kind.
Polymorphic technique calls and casting
It is doable to invoke particular strategies in a polymorphic name, however doing it comes at the price of flexibility. Right here’s an instance:
public summary class MetalGearCharacter {
summary void useWeapon(String weapon);
}
public class BigBoss extends MetalGearCharacter {
@Override
void useWeapon(String weapon) {
System.out.println("Huge Boss is utilizing a " + weapon);
}
void giveOrderToTheArmy(String orderMessage) {
System.out.println(orderMessage);
}
}
public class SolidSnake extends MetalGearCharacter {
void useWeapon(String weapon) {
System.out.println("Stable Snake is utilizing a " + weapon);
}
}
public class UseSpecificMethod {
public static void executeActionWith(MetalGearCharacter metalGearCharacter) {
metalGearCharacter.useWeapon("SOCOM");
// The under line would not work
// metalGearCharacter.giveOrderToTheArmy("Assault!");
if (metalGearCharacter instanceof BigBoss) {
((BigBoss) metalGearCharacter).giveOrderToTheArmy("Assault!");
}
}
public static void foremost(String... specificPolymorphismInvocation) {
executeActionWith(new SolidSnake());
executeActionWith(new BigBoss());
}
}
The method we’re utilizing right here is casting, or intentionally altering the thing kind at runtime.
Observe that it’s doable to invoke a selected technique solely when casting the generic kind to the particular kind. A superb analogy could be saying explicitly to the compiler, “Hey, I do know what I’m doing right here, so I’m going to solid the thing to a selected kind and use a selected technique.”
Referring to the above instance, there is a vital motive the compiler refuses to just accept particular technique invocation: the category that’s being handed might be SolidSnake
. On this case, there isn’t a approach for the compiler to make sure each subclass of MetalGearCharacter
has the giveOrderToTheArmy
technique declared.
Get the code: Get the supply code for this problem and run your individual assessments.
Reserved key phrases
Take note of the reserved phrase instanceof
. Earlier than invoking the particular technique we’ve requested if MetalGearCharacter
is “instanceof
” BigBoss
. If it wasn’t a BigBoss
occasion, we’d obtain the next exception message:
Exception in thread "foremost" java.lang.ClassCastException: com.javaworld.javachallengers.polymorphism.specificinvocation.SolidSnake can't be solid to com.javaworld.javachallengers.polymorphism.specificinvocation.BigBoss
What if we wished to reference an attribute or technique from a Java superclass? On this case, we might use the tremendous
reserved phrase. For instance:
public class JavaMascot {
void executeAction() {
System.out.println("The Java Mascot is about to execute an motion!");
}
}
public class Duke extends JavaMascot {
@Override
void executeAction() {
tremendous.executeAction();
System.out.println("Duke goes to punch!");
}
public static void foremost(String... superReservedWord) {
new Duke().executeAction();
}
}
Utilizing the reserved phrase tremendous
in Duke
’s executeAction
technique invokes the superclass technique. We then execute the particular motion from Duke
. That’s why we will see each messages within the output under:
The Java Mascot is about to execute an motion!
Duke goes to punch!
Frequent errors with polymorphism
- It’s a standard mistake to assume it’s doable to invoke a selected technique with out utilizing casting.
- One other mistake is being not sure what technique will likely be invoked when instantiating a category polymorphically. Keep in mind that the strategy to be invoked is the strategy of the created occasion.
- Additionally do not forget that technique overriding isn’t technique overloading.
- It’s not possible to override a technique if the parameters are completely different. It is feasible to vary the return kind of the overridden technique if the return kind is a subclass of the superclass technique.
What to recollect about polymorphism
- The created occasion will decide what technique will likely be invoked when utilizing polymorphism.
- The
@Override
annotation obligates the programmer to make use of an overridden technique; if not, there will likely be a compiler error. - Polymorphism can be utilized with regular courses, summary courses, and interfaces.
- Most design patterns rely upon some type of polymorphism.
- The one approach to make use of a selected technique in your polymorphic subclass is by utilizing casting.
- It’s doable to design a robust construction in your code utilizing polymorphism.
Take the Java polymorphism problem!
Let’s check out what you’ve discovered about polymorphism and inheritance. On this problem, you’re given a handful of strategies from Matt Groening’s The Simpsons, and your problem is to infer what the output for every class will likely be. To start out, analyze the next code fastidiously:
public class PolymorphismChallenge {
static summary class Simpson {
void discuss() {
System.out.println("Simpson!");
}
protected void prank(String prank) {
System.out.println(prank);
}
}
static class Bart extends Simpson {
String prank;
Bart(String prank) { this.prank = prank; }
protected void discuss() {
System.out.println("Eat my shorts!");
}
protected void prank() {
tremendous.prank(prank);
System.out.println("Knock Homer down");
}
}
static class Lisa extends Simpson {
void discuss(String toMe) {
System.out.println("I like Sax!");
}
}
public static void foremost(String... doYourBest) {
new Lisa().discuss("Sax :)");
Simpson simpson = new Bart("D'oh");
simpson.discuss();
Lisa lisa = new Lisa();
lisa.discuss();
((Bart) simpson).prank();
}
}
What do you assume? What’s going to the ultimate output be? Don’t use an IDE to determine this out! The purpose is to enhance your code evaluation abilities, so attempt to decide the output for your self.
Select your reply and also you’ll have the ability to discover the right reply under.
A)
I like Sax!
D'oh
Simpson!
D'oh
B)
Sax :)
Eat my shorts!
I like Sax!
D'oh
Knock Homer down
C)
Sax :)
D'oh
Simpson!
Knock Homer down
D)
I like Sax!
Eat my shorts!
Simpson!
D'oh
Knock Homer down
Fixing the problem
For the next technique invocation:
new Lisa().discuss("Sax :)");
the output will likely be “I like Sax!
” That is  as a result of we’re passing a String
to the strategy and Lisa
has the strategy.
For the subsequent invocation:
Simpson simpson = new Bart("D'oh");
simpson.discuss();
The output will likely be “Eat my shorts!
” It is because we’re instantiating  the Simpson
kind with Bart
.
Now examine this one, which is slightly trickier: