Polymorphism and abstract class easily explained in Java
Tags: oop, polymorphism, java
Published: 2024-03-14 18:22:47

**Polymorphism** is one of the main concepts behind OOP, together with encapsulation and inheritance. Despite its definition being pretty straightforward, you might struggle in understanding the reasons why it is used and the benefits it can lead to.

Polymorphism literally means that _**an object can take on many forms**_.

Here is a very simple example of a scenario where we can benefit from using polymorphism. We are going to make use of an **abstract class** for the purpose, taking the opportunity to explain this concept as well.

Let's say we want to make a class representing a human saying hello in its own language.

Since saying hello is very specific to the language spoken by the person, a good candidate to start with would be in fact an abstract class called `Person`, containing a method called `sayHello` to be implemented by concrete classes extending it (an `EnglishPerson`, an `ItalianPerson`, a `SpanishPerson`, etc.)

Here is our `Person` class:

```
public abstract class Person {
    public abstract void sayHello();
}
```

As you can see an abstract class generally contains one or more methods declared without an implementation. 
Why? Because the class is too generic to have a single implementation, and it is expected to be extended by other classes that will then be required to implement such abstract method(s).

Let's create two more classes now: `SpanishPerson` and `ItalianPerson`:

```
public class SpanishPerson extends Person {
    @Override
    public void sayHello() {
        System.out.println("Hola");
    }
}
```

```
public class ItalianPerson extends Person {
    @Override
    public void sayHello() {
        System.out.println("Ciao");
    }
}
```

We have created two concrete classes extending our abstract class and implementing the single abstract method that was declared.

Now we can leverage polymorphism by writing this:

```
public class HelloDemo {
    public static void main(String[] args) {
        Person mattia = new ItalianPerson();
        Person dolores = new SpanishPerson();
        
        mattia.sayHello();
        dolores.sayHello();
    }
}
```

that will print:

```
Ciao
Hola
```

Basically with polymorphism we are able to **_assign a reference of a superclass to an instance of a subclass_**.
In our case, `mattia` and `dolores` are two references of the superclass `Person`, but in practice they are pointing to objects of type `ItalianPerson` and `SpanishPerson`, respectively.

To better understand the power of such concept let's introduce a new `Greeter` class containing a method that accepts an argument of type `Person` that will invoke its `sayHello` method as before.

```
public class Greeter {
    public void greet(Person person) {
        person.sayHello();
    }
}
```

Instead of creating two (or more) different greet methods, one with a parameter of type `ItalianPerson` and the other one with a parameter of type `SpanishPerson`, we can leverage polymorphism by using a single method with a parameter of the abstract superclass `Person` to which we can pass either an `ItalianPerson` or a `SpanishPerson` instance, just as shown below:

```
public class HelloDemo {
    public static void main(String[] args) {
        Person mattia = new ItalianPerson();
        Person dolores = new SpanishPerson();

        Greeter greeter = new Greeter();
        greeter.greet(mattia);
        greeter.greet(dolores);
    }
}
```

that again will print:

```
Ciao
Hola
```

making our code more extensible, reusable and clean.

Hope you enjoyed this short explanation of one of the core concepts of object oriented programming.
Please feel free to leave a comment for any feedback.

See you soon