Polymorphism in Java with Example



< Previous Next >

OOPS Tutorial


1. Intent/Definition

The process of representing one form in multiple forms is known as Polymorphism.

Polymorphism is derived from 2 Greek words: poly and morphs. The word "poly" means many and "morphs" means forms. So polymorphism means many forms.

Different definitions of Polymorphism are:

  1. Polymorphism let us perform a single action in different ways.
  2. Polymorphism allows you to define one interface and have multiple implementations
  3. We can create functions or reference variables which behaves differently in different programmatic context.
  4. Polymorphism means many forms.

Real world example of polymorphism


Suppose if you are in a classroom that time you behave like a student, when you are in the market at that time you behave like a customer, when you at your home at that time you behave like a son or daughter, Here one person present in different-different behaviors.



Let's understand the polymorphism with examples.

2. Implementation

Example: Payment Processing Example

In this Payment Processing Example, applying runtime polymorphism and it can have many forms at runtime. Refer below source code the single payment "p" instance can be used to pay by cash and credit card, payment p instance takes many forms here.

public class Polymorphism {

    public static void main(String[] args) {
        // Here the runtime polymorphism fundamental is not applied, 
        // as it is of single CashPayment form
        CashPayment c = new CashPayment();
        c.pay();

        // Now the initialization is done using runtime polymorphism and 
        // it can have many forms at runtime
        // Single payment "p" instance can be used to pay by cash and credit card
        Payment p = new CashPayment();
        p.pay(); // Pay by cash

        p = new CreditPayment();
        p.pay(); // Pay by creditcard
    }

}

/**
 * This represents payment interface
 */
interface Payment {
    public void pay();
}

/**
 * Cash IS-A Payment type
 * 
 * @author tirthalp
 * 
 */
class CashPayment implements Payment {

    // method overriding
    @Override
    public void pay() {
        System.out.println("This is cash payment");
    }

}

/**
 * Creditcard IS-A Payment type
 */
class CreditPayment implements Payment {

    // method overriding
    @Override
    public void pay() {
        System.out.println("This is credit card payment");
    }

}

3. Types of Polymorphism in Java

  1. Compile time polymorphism or method overloading or static banding
  2. Runtime polymorphism or method overriding or dynamic binding
When a type of the object is determined at a compiled time(by the compiler), it is known as static binding.
When a type of the object is determined at run-time, it is known as dynamic binding.

3.1 Compile time Polymorphism

If the class contains two or more methods having the same name and different arguments then it is method overloading.
The compiler will resolve the call to a correct method depending on the actual number and/or types of the passed parameters The advantage of method overloading is to increases the readability of the program.

Method Overloading: changing no. of arguments

In this example, we have created two methods, first, add() method performs the addition of two numbers and a second add method performs addition of three numbers.
In this example, we are creating static methods so that we don't need to create an instance for calling methods.
class Adder {
    static int add(int a, int b) {
        return a + b;
    }
    static int add(int a, int b, int c) {
        return a + b + c;
    }
}
class TestOverloading1 {
    public static void main(String[] args) {
        System.out.println(Adder.add(11, 11));
        System.out.println(Adder.add(11, 11, 11));
    }
}

Method Overloading: changing the data type of arguments

In this example, we have created two methods that differ in data type. The first add method receives two integer arguments and second add method receives two double arguments.
class Adder {
    static int add(int a, int b) {
        return a + b;
    }
    static double add(double a, double b) {
        return a + b;
    }
}
class TestOverloading2 {
    public static void main(String[] args) {
        System.out.println(Adder.add(11, 11));
        System.out.println(Adder.add(12.3, 12.6));
    }
}
Read more about method overloading here: https://www.javatpoint.com/method-overloading-in-java

3.2 Runtime Polymorphism

Runtime polymorphism is a process in which a call to an overridden method is resolved at runtime rather than compile-time.
In this process, an overridden method is called through the reference variable of a superclass. The determination of the method to be called is based on the object being referred to by the reference variable.
Let's first understand the upcasting before Runtime Polymorphism.

Upcasting 



When reference variable of Parent class refers to the object of Child class, it is known as upcasting.
For example:
class A {}
class B extends A {}
class Demo {
    public static void main(String[] args) {
        A a = new B(); //upcasting  
    }
}

Java Runtime Polymorphism Example: Shape Example


class Shape {
    void draw() {
        System.out.println("drawing...");
    }
}
class Rectangle extends Shape {
    void draw() {
        System.out.println("drawing rectangle...");
    }
}
class Circle extends Shape {
    void draw() {
        System.out.println("drawing circle...");
    }
}
class Triangle extends Shape {
    void draw() {
        System.out.println("drawing triangle...");
    }
}
class TestPolymorphism2 {
    public static void main(String args[]) {
        Shape s;
        s = new Rectangle();
        s.draw();
        s = new Circle();
        s.draw();
        s = new Triangle();
        s.draw();
    }
}
Output:
drawing rectangle...
drawing circle...
drawing triangle...

Java Runtime Polymorphism with Data Member

The method is overridden not applicable data members, so runtime polymorphism can't be achieved by data members.
In the example given below, both the classes have a data member speedlimit, we are accessing the data member by the reference variable of Parent class which refers to the subclass object. Since we are accessing the data member which is not overridden, hence it will access the data member of Parent class always.
Runtime polymorphism can't be achieved by data members
class Bike {
    int speedlimit = 90;
}
class Honda extends Bike {
    int speedlimit = 150;

    public static void main(String args[]) {
        Bike obj = new Honda();
        System.out.println(obj.speedlimit); //90  
    }
}
Output:
90
Let's try the below scenario: Here the BabyDog is not overriding the eat() method, so eat() method of Dog class is invoked. Note that if we are not using @Override annotation in this example.
class Animal {
    void eat() {
        System.out.println("animal is eating...");
    }
}
class Dog extends Animal {
    void eat() {
        System.out.println("dog is eating...");
    }
}
class BabyDog1 extends Dog {
    public static void main(String args[]) {
        Animal a = new BabyDog1();
        a.eat();
    }
}
Output:
dog is eating...

Polymorphism - Method Overloading vs Method Overriding

GitHub Repository

The source code of this article available on my GitHub repository at OOPS Concepts in Java.

Learn complete Java Programming with Examples

Related Oops Posts

Top Core Java Tutorials

  1. Java Tutorial for Beginners
  2. 50 Java Keywords
  3. JDBC 4.2 Tutorial
  4. All Java/J2EE Tutorial
  5. Java 8 Tutorial
  6. Java Collections Tutorial
  7. Java Exceptions Tutorial
  8. Java Generics Tutorial
  9. Java 8 Stream API Tutorial
  10. Java Wrapper Classes
  11. Java Arrays Guide
  12. Java Multithreading Tutorial
  13. Java Concurrency Tutorial
  14. Oops Concepts Tutorial
  15. Java String API Guide
  16. Java Reflection API Tutorial
  17. Java I/O Tutorial
  18. Date and Time API Tutorial
  19. JUnit 5 Tutorial
  20. JUnit 4 Tutorial
  21. Java XML Tutorial
  22. Google GSON Tutorial

Top Java EE Tutorials

  1. Spring Security Tutorial
  2. RabbitMQ Tutorial
  3. Hibernate ORM 5
  4. Java Persistence API
  5. Spring Boot 2 Tutorial
  6. Spring Core 5 Tutorial
  7. Spring MVC 5 Tutorial
  8. Spring Data JPA Tutorial
  9. Apache HttpClient Tutorial
  10. Spring Framework 5
  11. Apache Maven Tutorial
  12. JAX-RS Tutorial
  13. Jersey Rest Tutorial

Java Library Tutorials

  1. Java API Guides
  2. Java SQL Package Tutorial
  3. All Java/J2EE Tutorial
  4. Java Lang Package Tutorial
  5. Java Util Package Tutorial
  6. Java Lang Reflect Package Tutorial
  7. Java Time Package Tutorial
  8. Java IO Package Tutorial

Top Java Best Practices

  1. Java Enums and Annotations Best Practices
  2. Java Generics Best Practices
  3. JUnit Framework Best Practices
  4. Java Naming Conventions
  5. Single Responsibility Principle
  6. Liskov's Substitution Principle
  7. Interface Segregation Principle
  8. Dependency Inversion Principle
  9. Open Closed Principle
  10. Oops principles in java
  11. Restful API Best Practices
  12. JSP Best Practices
  13. Guide to JDBC Best Practices
  14. Collection Best Practices
  15. String Best Practices in Java
  16. Exception Handling Best Practices
  17. Synchronization Best Practices
  18. Guide to JDBC Best Practices
  19. Serialization Best Practices

 

Comments