7.3. Polymorphism in Java
Polymorphism means "many forms". In Java, it allows objects of different classes to be treated as objects of a common superclass. There are two types:
- Compile-time polymorphism (Method overloading)
- Runtime polymorphism (Method overriding)
Runtime Polymorphism Example
java
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog barks");
}
public void fetch() {
System.out.println("Dog fetches ball");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Cat meows");
}
public void scratch() {
System.out.println("Cat scratches furniture");
}
}
public class PolymorphismDemo {
public static void main(String[] args) {
// Polymorphic behavior
Animal myAnimal = new Dog(); // Animal reference, Dog object
myAnimal.makeSound(); // Output: Dog barks (runtime decision)
myAnimal = new Cat(); // Same reference, different object
myAnimal.makeSound(); // Output: Cat meows (runtime decision)
// Cannot access subclass-specific methods
// myAnimal.fetch(); // Compilation error
}
}
Polymorphism with Collections
java
import java.util.ArrayList;
import java.util.List;
class Shape {
public void draw() {
System.out.println("Drawing a shape");
}
public double getArea() {
return 0.0;
}
}
class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("Drawing a circle with radius " + radius);
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}
class Rectangle extends Shape {
private double width, height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("Drawing a rectangle " + width + "x" + height);
}
@Override
public double getArea() {
return width * height;
}
}
public class ShapeDemo {
public static void main(String[] args) {
List<Shape> shapes = new ArrayList<>();
shapes.add(new Circle(5.0));
shapes.add(new Rectangle(4.0, 6.0));
shapes.add(new Circle(3.0));
// Polymorphic method calls
for (Shape shape : shapes) {
shape.draw(); // Runtime polymorphism
System.out.println("Area: " + shape.getArea());
System.out.println("---");
}
}
}
Polymorphism in Method Parameters
java
class Employee {
protected String name;
public Employee(String name) {
this.name = name;
}
public void work() {
System.out.println(name + " is working");
}
}
class Manager extends Employee {
public Manager(String name) {
super(name);
}
@Override
public void work() {
System.out.println(name + " is managing the team");
}
}
class Developer extends Employee {
public Developer(String name) {
super(name);
}
@Override
public void work() {
System.out.println(name + " is writing code");
}
}
class Company {
// Method accepts any Employee subclass
public static void assignWork(Employee employee) {
employee.work(); // Polymorphic call
}
public static void main(String[] args) {
Employee emp1 = new Manager("Alice");
Employee emp2 = new Developer("Bob");
assignWork(emp1); // Output: Alice is managing the team
assignWork(emp2); // Output: Bob is writing code
}
}
The instanceof
Operator
java
public class InstanceOfDemo {
public static void main(String[] args) {
Animal animal = new Dog();
// Check object type at runtime
if (animal instanceof Dog) {
System.out.println("It's a dog!");
Dog dog = (Dog) animal; // Safe casting
dog.fetch();
}
if (animal instanceof Animal) {
System.out.println("It's an animal!");
}
// Pattern matching (Java 14+)
if (animal instanceof Dog d) {
d.fetch(); // No explicit casting needed
}
}
}
Polymorphism Benefits
- Code Flexibility: Easily extendable
- Maintainability: Changes affect multiple types
- Reusability: Common interfaces for different types
- Simplified Code: Single interface for multiple implementations