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("Fola"));
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
At a glance
- Purpose
- General-purpose application development
- File extension
- .java
- Runs in
- Java Virtual Machine
- Usually used with
- JDK and Java libraries
Specifications & further reading
Related Java documentation
Classes in Java are blueprints for creating objects, defining their properties (fields) and behaviors (methods). Java is a strictly object-oriented language where everything is encapsulated within classes. A class serves as a template that specifies what data an object will store and what operations it can perform.Interfaces
An interface defines a contract of methods that implementing classes must provide, without specifying how those methods work internally. Unlike a class, an interface cannot be instantiated directly - it only declares what a class can do, not how. A class uses the 'implements' keyword to fulfill an interface's contract, and a single class can implement multiple interfaces, which is Java's way of achieving a form of multiple inheritance.Abstract Classes
An abstract class is a class that cannot be instantiated directly and may contain both fully implemented methods and abstract methods (declared without a body, which subclasses must implement). Abstract classes sit between interfaces and regular classes: like an interface, they define a contract; like a regular class, they can hold state (fields) and provide shared, already-implemented behavior.Constructors
A constructor is a special method that runs automatically when an object is created with 'new', typically used to initialize the object's fields. A constructor shares its name with the class and has no return type, not even void. Java supports constructor overloading, letting a class offer multiple ways to construct an object, and constructor chaining with this(...), where one constructor calls another in the same class.