Skip to content

Polymorphism in Java (Part I), with Examples

Learn what polymorphism is in Java and how it works in object-oriented programming, with abstract classes, method overriding and a football team example.

You can download the project for this post by clicking HERE.

Polymorphism is one of the 4 pillars of object-oriented programming (OOP) along with Abstraction, Encapsulation and Inheritance. To understand what polymorphism is, it’s very important that you are pretty clear on the concept of Inheritance, so we recommend that you check out the post where we talk about Inheritance: Inheritance in Java, with examples.

To start with this post, we should say that the term "Polymorphism" is a word of Greek origin that means "many forms". This term is used in OOP "to refer to the property that makes it possible to send syntactically identical messages to objects of different types". Since this definition may be a bit hard to understand, we are going to explain it with the example we used in the post about inheritance, in which we wanted to simulate the behavior of the different members of the Spanish national football team; both the Players and the coaching staff (Coaches, Masseurs, etc…). For this example we are going to use the following class diagram:

PolimorfismoFutbol-diag

NOTE: in this diagram and from now on we are not going to include the constructors and the getter and setter methods, so that the diagram doesn’t end up big and “unreadable”, although in a good class diagram they should appear in order to respect the OOP principle of encapsulation

 

In this example we are going to have a parent class (SelecciónFutbol) that will contain the attributes and methods common to all the members of the Spanish national football team (Players, Coaches, Masseurs, etc.) and in it we are going to implement the methods for the "generic" behavior that all the members of the team must have. As we said in the post about inheritance, inheritance is nothing more than pulling out the "common factor" of the code we write, so the attributes and methods of the SeleccionFutbol class will also be available to the objects of the Futbolista, Entrenador and Masajista classes. Before moving on, let’s show the code of the "SeleccionFutbol" class to see some peculiarities:


public abstract class SeleccionFutbol {

	protected int id;
	protected String nombre;
	protected String apellidos;
	protected int edad;

	// constructors, getters and setters

	public void viajar() {
	     System.out.println("Viajar (Clase Padre)");
	}

	public void concentrarse() {
	     System.out.println("Concentrarse (Clase Padre)");
	}

	// IMPORTANT -> ABSTRACT METHOD => it is not implemented in the abstract class but it is in the child classes
	public abstract void entrenamiento();

	public void partidoFutbol() {
	     System.out.println("Asiste al Partido de Fútbol (Clase Padre)");
	}
}

The first thing that should catch our attention when looking at this code is that we use the reserved word "abstract" twice. This word tells us that the "SeleccionFutbol" class is an abstract class, and abstract classes cannot be instantiated, so we will never be able to do a "new SeleccionFutbol()". Another thing we see is that we also use the reserved word abstract on a method (the entrenamiento method). This means that all the child classes of the "SeleccionFubol" class must implement that method, no exceptions. So, given what we just said, and given that the word "Polymorphism" means "many forms", you can deduce that the "SeleccionFutbol" class is a class that can take on different forms, and in this example it can take the forms of "Futbolista", "Entrenador" and "Masajista".

Ejm_polimorfismo_jarroba

As we can see, an "Entrenador", a "Futbolista" and a "Masajista" belong to the same parent class, and that’s why they are instantiated by saying that it is a SeleccionFutbol, while being new objects of the child classes. On the other hand, we see that objects of an abstract class cannot be created, so creating the "casillas" object gives us an error.

Now, if we have defined an abstract method in the parent class that must be implemented in the child classes, how do we do it? Well, let’s take it step by step. One really good thing about inheritance and polymorphism is that child classes not only inherit the methods (or the implementation of the methods) of the parent classes, but also child classes can specialize.  This means that a child class can "override" the methods of its parent class; that is, that method can be written again, and that’s where the specialization comes from. To see this, let’s look at the implementation of the child classes:


public class Futbolista extends SeleccionFutbol {

   private int dorsal;
   private String demarcacion;

   // constructor, getters and setters

   @Override
   public void entrenamiento() {
      System.out.println("Realiza un entrenamiento (Clase Futbolista)");
   }

   @Override
   public void partidoFutbol() {
      System.out.println("Juega un Partido (Clase Futbolista)");
   }

   public void entrevista() {
      System.out.println("Da una Entrevista");
   }
}

public class Entrenador extends SeleccionFutbol {

   private int idFederacion;

   // constructor, getters and setters
	
   @Override
   public void entrenamiento() {
      System.out.println("Dirige un entrenamiento (Clase Entrenador)");
   }

   @Override
   public void partidoFutbol() {
      System.out.println("Dirige un Partido (Clase Entrenador)");
   }

   public void planificarEntrenamiento() {
      System.out.println("Planificar un Entrenamiento");
   }
}

public class Masajista extends SeleccionFutbol {

   private String titulacion;
   private int aniosExperiencia;

   // constructor, getters and setters
	
   @Override
   public void entrenamiento() {
      System.out.println("Da asistencia en el entrenamiento (Clase Masajista)");
   }

   public void darMasaje() {
      System.out.println("Da un Masaje");
   }
}

As we can see in the code, all the child classes implement the "entrenamiento()" method since, as we said, because it is an abstract method in the parent class, all the child classes must have that method. On the other hand, we notice in the code that above the "entrenamiento()" method and other methods we have the annotation "@Override". This annotation is used to indicate in the code that we are "rewriting or specializing" a method that is in the parent class and that we want to redefine in the child class. If you look closely, this annotation appears only and exclusively on the methods of the child classes that are defined in the parent class, so when those methods are called, the child classes will run the method redefined in the child class, and the ones that haven’t redefined it will run the parent class method. In the following image we can see how we make these specializations:

Polimorfismo_especializacion_jarroba

With all this we can now start running the program that will simulate the behavior of the members of the Spanish team and see the different forms each of them takes. To do that, let’s start by showing the following piece of code:


public class Main {

	// ArrayList of SeleccionFutbol objects. Regardless of the child class the object belongs to
	public static ArrayList<SeleccionFutbol> integrantes = new ArrayList<SeleccionFutbol>();

	public static void main(String[] args) {
		
		SeleccionFutbol delBosque = new Entrenador(1, "Vicente", "Del Bosque", 60, 28489);
		SeleccionFutbol iniesta = new Futbolista(2, "Andres", "Iniesta", 29, 6, "Interior Derecho");
		SeleccionFutbol raulMartinez = new Masajista(3, "Raúl", "Martinez", 41, "Licenciado en Fisioterapia", 18);

		integrantes.add(delBosque);
		integrantes.add(iniesta);
		integrantes.add(raulMartinez);

		// CONCENTRATION
		System.out.println("Todos los integrantes comienzan una concentracion. (Todos ejecutan el mismo método)");
		for (SeleccionFutbol integrante : integrantes) {
			System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");
			integrante.concentrarse();
		}

		// TRAVEL
		System.out.println("nTodos los integrantes viajan para jugar un partido. (Todos ejecutan el mismo método)");
		for (SeleccionFutbol integrante : integrantes) {
			System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");
			integrante.viajar();
		}

      .........
}

As we can see, we have created three objects of the SeleccionFutbol class that take one of the three forms they can adopt (Entrenador, Futbolista and Masajista)  and we put them in an “ArrayList” of “SeleccionFutbol” objects. Now, when we run this piece of code we will see that they all behave the same way when it comes to "concentrarse()" and "viajar()", so they will run the parent class method:


Todos los integrantes comienzan una concentracion. (Todos ejecutan el mismo método)
Vicente Del Bosque -> Concentrarse (Clase Padre)
Andres Iniesta -> Concentrarse (Clase Padre)
Raúl Martinez -> Concentrarse (Clase Padre)

Todos los integrantes viajan para jugar un partido. (Todos ejecutan el mismo método)
Vicente Del Bosque -> Viajar (Clase Padre)
Andres Iniesta -> Viajar (Clase Padre)
Raúl Martinez -> Viajar (Clase Padre)

Nothing new or surprising so far, but now let’s see how each of the members, when the same methods ("entrenamiento()" and "partidoFutbol()") are called, behaves differently:


     ........
// TRAINING
System.out.println("nEntrenamiento: Todos los integrantes tienen su función en un entrenamiento (Especialización)");
for (SeleccionFutbol integrante : integrantes) {
	System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");
	integrante.entrenamiento();
}

// FOOTBALL MATCH
System.out.println("nPartido de Fútbol: Todos los integrantes tienen su función en un partido (Especialización)");
for (SeleccionFutbol integrante : integrantes) {
	System.out.print(integrante.getNombre() + " " + integrante.getApellidos() + " -> ");
	integrante.partidoFutbol();
}
     ........

Here is the result of running this piece of code:


Entrenamiento: Todos los integrantes tienen su función en un entrenamiento (Especialización)
Vicente Del Bosque -> Dirige un entrenamiento (Clase Entrenador)
Andres Iniesta -> Realiza un entrenamiento (Clase Futbolista)
Raúl Martinez -> Da asistencia en el entrenamiento (Clase Masajista)

Partido de Fútbol: Todos los integrantes tienen su función en un partido (Especialización)
Vicente Del Bosque -> Dirige un Partido (Clase Entrenador)
Andres Iniesta -> Juega un Partido (Clase Futbolista)
Raúl Martinez -> Asiste al Partido de Fútbol (Clase Padre)

In this case we see that all the members run the "entrenamiento()" method differently, since this method is abstract in the parent class, so we force the child classes to implement it. On the other hand, when running the "partidoFutbol()" method we see that the Masajista object uses the method implemented in the parent class, whereas the Futbolista and Entrenador objects run their "re-implemented or specialized" methods that were rewritten in their own classes.

Finally, let’s see that each of the objects can run its own methods that only they have, such as "planificarEntrenamiento(), entrevista() and  darMasaje()", which can only be run by objects of the Entrenador, Futbolista and Masajista classes respectively:


     ........
// PLAN TRAINING
System.out.println("nPlanificar Entrenamiento: Solo el entrenador tiene el método para planificar un entrenamiento:");
System.out.print(delBosque.getNombre() + " " + delBosque.getApellidos() + " -> ");
((Entrenador) delBosque).planificarEntrenamiento();

// INTERVIEW
System.out.println("nEntrevista: Solo el futbolista tiene el método para dar una entrevista:");
System.out.print(iniesta.getNombre() + " " + iniesta.getApellidos() + " -> ");
((Futbolista) iniesta).entrevista();

// MASSAGE
System.out.println("nMasaje: Solo el masajista tiene el método para dar un masaje:");
System.out.print(raulMartinez.getNombre() + " " + raulMartinez.getApellidos() + " -> ");
((Masajista) raulMartinez).darMasaje();
     ........

The result of running this piece of code is the following:


Planificar Entrenamiento: Solo el entrenador tiene el método para planificar un entrenamiento:
Vicente Del Bosque -> Planificar un Entrenamiento

Entrevista: Solo el futbolista tiene el método para dar una entrevista:
Andres Iniesta -> Da una Entrevista

Masaje: Solo el masajista tiene el método para dar un masaje:
Raúl Martinez -> Da un Masaje

CONCLUSIONS AND CLARIFICATIONS:

As we have seen, polymorphism is a slightly more advanced concept than inheritance, and it can be very useful when you want to build a hierarchy and give a common pattern of behavior to a series of objects that inherit from the same class. In this post we haven’t covered everything about polymorphism, since there is still a slightly more advanced concept in Java (and in other languages too), the "Interface" (pure abstract classes), which we will cover in another post to finish seeing what polymorphism is.

Finally, if you are just starting out with OOP, it’s very likely that you won’t see much sense in this polymorphism thing, and that’s normal at first. All I can tell you is that with experience you come to see the point of polymorphism, so if you have to do an assignment at university or whatever in which you have to use polymorphism, try to understand it and do what they ask, because understanding it 100% is hard and it takes experience.

“Polymorphism in Java (Part I), with Examples” by Ricardo Moya at jarroba.com, licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0. Registered at Safe Creative.

Ricardo Moya

I work in Machine Learning and Big Data. I like learning new technologies and explaining them as clearly as I can on this site.

You may also like

Inheritance in Java, with Examples

Learn what inheritance is in object-oriented programming and how it works in Java, using extends, protected and super with a clear, practical example.

Apr 8, 2014

Comments

Leave a comment


This site uses Akismet to reduce spam. Learn how your comment data is processed.