Menu
Theme
Bachelor of Science in Computer Science
Course Content

Polymorphism

Object Oriented Programming (Java)

Polymorphism: The "Chameleon" of Java Programming!

Sasa! I hope you are ready for one of the coolest topics in Object-Oriented Programming. At first, the word "Polymorphism" sounds like something from a science fiction movie, right? But don't worry, we are going to break it down. It's actually a very powerful and elegant concept that, once you understand it, will make your code much smarter and more flexible.

Think about a chameleon. In one moment it's brown on a tree trunk, the next it's green on a leaf. It's the same chameleon but it takes on different forms depending on the situation. That's exactly what polymorphism is!

In Greek, Poly means "many" and Morph means "forms". So, Polymorphism simply means "many forms". In Java, it's the ability of an object to take on many forms.

Image Suggestion: A vibrant, colourful digital art image of a chameleon on a branch. The branch transitions from brown wood to green leaves, and the chameleon's skin is changing colour at the transition point. The word "POLYMORPHISM" is subtly blended into the background foliage.

Why is This Important? The "One Remote to Rule Them All" Idea

Imagine you have a different remote control for your TV, your sound system, and your fan. It's a mess! What if you could have ONE remote with a "Power On" button that knows whether to turn on the TV, the sound system, or the fan? That's the power of polymorphism. It lets us perform a single action in different ways. It makes our code reusable, flexible, and easier to manage.

There are two main types of polymorphism in Java. Let's look at them one by one.

1. Compile-Time Polymorphism (Method Overloading)

This is the easier one to understand. It's also called "static polymorphism". It happens when you have multiple methods in the same class with the same name but different parameters (different number of arguments, or different types of arguments).

The Java compiler decides which method to call at compile time, based on the arguments you provide.

Kenyan Example: Ordering at a Kiosk

Think about ordering a snack. You can say:

  • "Nipatie KDF." (You get one KDF)
  • "Nipatie KDF mbili." (You get two KDFs by specifying a number)
  • "Nipatie KDF na chai." (You get a KDF and tea by specifying another item)

The action is the same: "get KDF". But you provide different information (parameters), and you get a slightly different result. This is method overloading!

Code Example: A Simple Calculator

Let's create a class that can add numbers. It can add two integers, or it can add three integers, or it can add two doubles.


class SimpleCalculator {
    // Method 1: Adds two integers
    public int add(int a, int b) {
        System.out.println("Adding two integers...");
        return a + b;
    }

    // Method 2: Adds three integers (Same name, different parameters)
    public int add(int a, int b, int c) {
        System.out.println("Adding three integers...");
        return a + b + c;
    }

    // Method 3: Adds two doubles (Same name, different parameter types)
    public double add(double a, double b) {
        System.out.println("Adding two doubles...");
        return a + b;
    }
}

public class Main {
    public static void main(String[] args) {
        SimpleCalculator myCalc = new SimpleCalculator();
        
        System.out.println("Sum is: " + myCalc.add(5, 10));       // Calls Method 1
        System.out.println("Sum is: " + myCalc.add(5, 10, 20));  // Calls Method 2
        System.out.println("Sum is: " + myCalc.add(5.5, 10.2));  // Calls Method 3
    }
}

2. Runtime Polymorphism (Method Overriding)

This is the big one! It's the chameleon we were talking about. This type of polymorphism is achieved through inheritance and happens at "runtime" (when the program is actually running).

It allows a subclass or child class to provide a specific implementation of a method that is already provided by its superclass or parent class. The parent defines a general action, and the child defines how it specifically performs that action.

Kenyan Example: The Mighty Matatu!

All matatus on the road have a basic function: `move()`. But how they move can be very different! A regular 14-seater City Hoppa moves differently from a flashy, souped-up Nganya from Rongai or Umoja.

  • A general Matatu has a `hoot()` method. It probably makes a simple "Beep! Beep!" sound.
  • A Nganya is also a Matatu, so it inherits the `hoot()` method. But a Nganya will override it to play a loud, custom horn sound, maybe a train horn or a song!

Same action (`hoot()`), different behaviour. That is method overriding in action!

Image Suggestion: A split-screen illustration. On the left, a standard, calm City Hoppa matatu with a simple "Beep!" speech bubble. On the right, a flashy, colourful Nganya with graffiti art, big speakers, and a massive, chaotic "BWOOOMP! BWOOOMP! [Reggae Horn Sound]" speech bubble. The title above is "Method Overriding".

Visualizing the Matatu Hierarchy

Here is a simple diagram to show the relationship. The arrow means "is a". So, a Nganya "is a" Matatu.


      +-----------------+
      |     Matatu      |
      |-----------------|
      | + void move()   |
      | + void hoot()   |
      +-----------------+
              ^
              | (is a)
    +-------------------------+
    |         Nganya          |
    |-------------------------|
    | @Override void hoot()   |  <-- Provides its own version!
    +-------------------------+

Code Example: The Matatu Fleet


// Parent Class
class Matatu {
    public void move() {
        System.out.println("The matatu is moving along its route.");
    }
    
    public void hoot() {
        System.out.println("Beep! Beep!");
    }
}

// Child Class inheriting from Matatu
class Nganya extends Matatu {
    // Overriding the hoot() method of the Matatu class
    @Override
    public void hoot() {
        System.out.println("BWOOOOMP! BWOOOOMP! PLAYS A LOUD REGGAE HORN!");
    }
}

public class UmoinnerSacco {
    public static void main(String[] args) {
        Matatu myMatatu; // A reference of type Matatu

        myMatatu = new Matatu(); // Pointing to a standard Matatu object
        myMatatu.hoot(); // Outputs: Beep! Beep!

        System.out.println("--- Here comes the new ride! ---");

        myMatatu = new Nganya(); // Now, the SAME reference is pointing to a Nganya object
        myMatatu.hoot(); // Outputs: BWOOOOMP! BWOOOOMP! PLAYS A LOUD REGGAE HORN!
    }
}

Look at the `main` method. The variable `myMatatu` is of type `Matatu`, but it can hold an object of `Matatu` OR an object of its child class, `Nganya`. When `hoot()` is called, Java checks at runtime which object `myMatatu` is actually pointing to and calls the correct version of the method. So powerful!

Polymorphism with Calculations: Shapes

Let's see a more mathematical example. All shapes have an area, but the formula to calculate it is different for each shape.


// Parent Class
abstract class Shape {
    // An abstract method has no body, forcing subclasses to implement it
    abstract double calculateArea(); 
}

// Child Class 1
class Circle extends Shape {
    double radius;
    
    Circle(double r) {
        this.radius = r;
    }
    
    @Override
    double calculateArea() {
        // Formula for area of a circle
        // Area = π * r^2
        return Math.PI * radius * radius;
    }
}

// Child Class 2
class Rectangle extends Shape {
    double length;
    double width;

    Rectangle(double l, double w) {
        this.length = l;
        this.width = w;
    }

    @Override
    double calculateArea() {
        // Formula for area of a rectangle
        // Area = length * width
        return length * width;
    }
}

public class GeometryClass {
    public static void main(String[] args) {
        Shape myShape; // A single reference of type Shape

        myShape = new Circle(7.0); // It's a Circle now
        System.out.println("Area of Circle: " + myShape.calculateArea());

        myShape = new Rectangle(10.0, 5.0); // Now it's a Rectangle
        System.out.println("Area of Rectangle: " + myShape.calculateArea());
    }
}

Key Takeaways

  • Polymorphism means "many forms". It allows an object to behave differently in different situations.
  • Method Overloading (Compile-Time): Same method name, different parameters. Easy!
  • Method Overriding (Runtime): A subclass provides a specific implementation for a method from its parent class. This is where the real power lies!
  • It makes your code super flexible. You can write code that works with parent class objects, and it will automatically work with any new child classes you create later.

You've got this! Polymorphism is a cornerstone of good object-oriented design. Play around with these examples. Try creating your own classes—maybe an `Animal` parent class with `Dog` and `Cat` children that override a `makeSound()` method. The more you practice, the clearer it will become. Happy coding!

Pro Tip

Take your own short notes while going through the topics.

KenyaEdu
Add KenyaEdu to Home Screen
For offline access and faster experience