Syntax
ParentType variable = new ChildType();Examples
Runtime Polymorphism with Method Overriding
The same method call produces different behavior depending on the actual object type.
class Animal {
public void makeSound() {
System.out.println("Some generic sound");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
Animal[] animals = { new Dog(), new Cat(), new Animal() };
for (Animal a : animals) {
a.makeSound(); // calls the correct version for each actual object type
}
// Woof!
// Meow!
// Some generic soundPolymorphism with Interfaces
Treating different implementing classes uniformly through a shared interface type.
interface Shape {
double area();
}
class Circle implements Shape {
private double radius;
public Circle(double radius) { this.radius = radius; }
public double area() { return Math.PI * radius * radius; }
}
class Square implements Shape {
private double side;
public Square(double side) { this.side = side; }
public double area() { return side * side; }
}
Shape[] shapes = { new Circle(3), new Square(4) };
for (Shape s : shapes) {
System.out.printf("Area: %.2f%n", s.area());
}Polymorphism in Method Parameters
A method that accepts the parent type can work with any subclass, without needing to know the specific type.
class Employee {
protected String name;
public Employee(String name) { this.name = name; }
public double calculatePay() { return 0; }
}
class FullTime extends Employee {
public FullTime(String name) { super(name); }
@Override
public double calculatePay() { return 5000; }
}
class Contractor extends Employee {
public Contractor(String name) { super(name); }
@Override
public double calculatePay() { return 3000; }
}
public class Payroll {
public static void printPay(Employee e) { // works with ANY Employee subclass
System.out.println(e.name + ": $" + e.calculatePay());
}
public static void main(String[] args) {
printPay(new FullTime("John"));
printPay(new Contractor("Zain"));
}
}Best practices
- Declare variables, parameters, and return types using the parent type or interface when you want to write flexible, extensible code
- Rely on polymorphism instead of type-checking with instanceof and manual casting where possible - let overridden methods handle the differences
- Remember polymorphism applies to overridden instance methods, not fields or static methods, which are resolved based on the declared type instead
- Design parent classes/interfaces around behavior that genuinely varies by subclass, so polymorphism adds real value rather than just ceremony
Runtime & versions
Java Virtual Machine. Feature availability depends on the language and runtime version used by your project; consult the official reference below.
Java Language Specification