Java Tutorial

Operators

Flow Control

String

Number and Date

Built-in Classes

Array

Class and Object

Inheritance and Polymorphism

Exception Handling

Collections, Generics and Enumerations

Reflection

Input/Output Stream

Annotation

Java Polymorphism

Polymorphism is one of the four fundamental principles of object-oriented programming (OOP), alongside encapsulation, inheritance, and abstraction. Polymorphism allows objects of different classes to be treated as objects of a common superclass, which enables you to write more flexible and reusable code. In this tutorial, we will cover the basics of polymorphism in Java, including method overriding and interfaces.

  • Method overriding:

Method overriding is a form of polymorphism where a subclass provides its own implementation for a method that already exists in its superclass. This allows the subclass to inherit methods and fields from the superclass and customize its behavior.

Example:

class Animal {
    void makeSound() {
        System.out.println("The animal makes a sound");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("The dog barks");
    }
}

class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("The cat meows");
    }
}

In this example, the Dog and Cat classes override the makeSound() method from the Animal class. This allows each class to provide its own implementation of the method.

  • Using polymorphism with method overriding:

With method overriding, you can use a reference of the superclass type to refer to objects of the subclass type, and the appropriate method implementation will be called at runtime based on the actual object type.

Example:

public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Animal();
        Animal myDog = new Dog();
        Animal myCat = new Cat();

        myAnimal.makeSound(); // Output: The animal makes a sound
        myDog.makeSound();    // Output: The dog barks
        myCat.makeSound();    // Output: The cat meows
    }
}
  • Polymorphism with interfaces:

Interfaces in Java provide another way to achieve polymorphism. A class can implement one or more interfaces, and objects of that class can be treated as instances of the interface.

Example:

interface Drawable {
    void draw();
}

class Circle implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing a circle");
    }
}

class Square implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing a square");
    }
}

In this example, both Circle and Square classes implement the Drawable interface and provide their own implementation of the draw() method.

  • Using polymorphism with interfaces:

With interfaces, you can use a reference of the interface type to refer to objects of the implementing class, and the appropriate method implementation will be called at runtime based on the actual object type.

Example:

public class Main {
    public static void main(String[] args) {
        Drawable[] drawables = new Drawable[2];
        drawables[0] = new Circle();
        drawables[1] = new Square();

        for (Drawable drawable : drawables) {
            drawable.draw();
        }
    }
}

Output:

Drawing a circle
Drawing a square

In this tutorial, we covered the basics of polymorphism in Java, including method overriding and interfaces. Polymorphism allows objects of different classes to be treated as objects of a common superclass or interface, which enables you to write more flexible and reusable code in your Java applications.

  1. Java Method Overriding and Polymorphism:

    • Method overriding allows a subclass to provide a specific implementation of a method that is already defined in its superclass.
    class Animal {
        void sound() {
            System.out.println("Animal makes a sound");
        }
    }
    
    class Dog extends Animal {
        void sound() {
            System.out.println("Dog barks");
        }
    }
    
  2. Compile-time vs Runtime Polymorphism in Java:

    • Compile-time polymorphism is achieved through method overloading, while runtime polymorphism is achieved through method overriding.
    // Compile-time polymorphism (method overloading)
    class MathOperations {
        int add(int a, int b) {
            return a + b;
        }
    
        double add(double a, double b) {
            return a + b;
        }
    }
    
  3. Polymorphism in Java with Examples:

    • Polymorphism allows objects of different types to be treated as objects of a common type.
    Animal myDog = new Dog();
    myDog.sound(); // Calls Dog's overridden sound method
    
  4. Java Polymorphism vs Encapsulation:

    • Polymorphism and encapsulation are two different concepts. Polymorphism is about multiple forms of a method, while encapsulation is about bundling data and methods that operate on the data within a single unit (class).
    class EncapsulationExample {
        private int data;
    
        public int getData() {
            return data;
        }
    
        public void setData(int newData) {
            data = newData;
        }
    }
    
  5. Dynamic Method Dispatch in Java:

    • Dynamic method dispatch allows the JVM to determine the appropriate method to call at runtime, based on the type of object.
    Animal myAnimal = new Dog(); // Upcasting
    myAnimal.sound(); // Calls Dog's overridden sound method at runtime
    
  6. Polymorphism and Interfaces in Java:

    • Interfaces provide a way to achieve polymorphism by allowing classes to implement the same set of methods defined in the interface.
    interface Shape {
        void draw();
    }
    
    class Circle implements Shape {
        void draw() {
            System.out.println("Drawing a circle");
        }
    }
    
  7. Covariant Return Types and Polymorphism in Java:

    • Covariant return types allow a method in a subclass to return a subtype of the type returned by the overridden method in the superclass.
    class Animal {
        Animal reproduce() {
            return new Animal();
        }
    }
    
    class Dog extends Animal {
        @Override
        Dog reproduce() {
            return new Dog();
        }
    }
    
  8. Abstract Classes and Polymorphism in Java:

    • Abstract classes can have abstract methods that are overridden by concrete subclasses, achieving polymorphism.
    abstract class Shape {
        abstract void draw();
    }
    
    class Circle extends Shape {
        void draw() {
            System.out.println("Drawing a circle");
        }
    }
    
  9. Java Polymorphism and Method Signatures:

    • Polymorphism is based on method signatures, which include the method name and parameter types.
    class MathOperations {
        int add(int a, int b) {
            return a + b;
        }
    
        double add(double a, double b) {
            return a + b;
        }
    }