Inheritance and Polymorphism in Java

Master inheritance, abstract and sealed types, record classes, method overriding, Object class methods, polymorphism, casting, instanceof operator, and pattern matching for the OCP 21 exam.

Table of Contents

1. Inheritance Basics

Inheritance allows a class to inherit fields and methods from another class. The class being inherited from is called the superclass or parent class, and the inheriting class is called the subclass or child class.

1.1 extends Keyword

Example:
// Parent class (superclass) class Animal {
    String name;
    void eat() {
        System.out.println(name +" is eating");
    }
} // Child class (subclass) class Dog extends Animal {
void bark() {
    System.out.println(name +" is barking");
}
} Dog dog = new Dog();
dog.name ="Buddy";
dog.eat();
// Inherited method dog.bark();
// Own
method

1.2 Inheritance Rules

  • Java supports single inheritance (one parent class)
  • All classes inherit from Object class (except Object itself)
  • Private members are not inherited (but exist in subclass)
  • Constructors are not inherited
  • Subclass can access protected and public members

2. Method Overriding

Method overriding allows a subclass to provide a specific implementation of a method defined in its superclass.

2.1 Overriding Rules

  • Method signature must match exactly
  • Return type must be same or covariant (subtype)
  • Access modifier cannot be more restrictive
  • Cannot override final methods
  • Cannot override static methods (method hiding instead)
  • Must use @Override annotation (recommended)
Example:
class Animal {
    public void makeSound() {
        System.out.println("Some sound");
    }
protected String getInfo() {
    return"Animal";
}
} class Dog extends Animal {
@Override public void makeSound() {
    // Overriding System.out.println("Woof!");
}
@Override public String getInfo() {
    // Can make more accessible return"Dog";
} // Covariant return type @Override public Dog getAnimal() {
// Returns Dog instead of Animal return this;
}
} Animal animal = new Dog();
animal.makeSound();
//"Woof!" (polymorphism)

2.2 super Keyword

Example:
class Animal {
    void eat() {
        System.out.println("Animal is eating");
    }
} class Dog extends Animal {
@Override void eat() {
    super.eat();
    // Call parent's method System.out.println("Dog is eating");

    }
}

3. Abstract Classes

Abstract classes cannot be instantiated. They can contain abstract methods (without implementation) and concrete methods.

3.1 Abstract Class Syntax

Example:
// Abstract class abstract class Animal {
    String name;
    // Abstract method (no implementation) abstract void makeSound();
    // Concrete method void eat() {
        System.out.println(name +" is eating");
    }
} // Concrete subclass must implement abstract methods class Dog extends Animal {
@Override void makeSound() {
    System.out.println("Woof!");
}
} // Cannot instantiate abstract class // Animal animal = new Animal();
// Compilation error // Can instantiate concrete subclass Dog dog = new Dog();
dog.makeSound();

3.2 Abstract Class Rules

  • Cannot be instantiated
  • Can have abstract and concrete methods
  • Can have fields, constructors, and initializers
  • Subclasses must implement all abstract methods (or be abstract themselves)
  • Can extend other classes and implement interfaces

4. Sealed Classes

Sealed classes (Java 17+) restrict which classes can extend them. This provides controlled inheritance.

4.1 Sealed Class Syntax

Example:
// Sealed class - only permits specified classes sealed class Shape permits Circle, Rectangle, Triangle {
    abstract double area();
} // Permitted classes must be final, sealed, or non-sealed final class Circle extends Shape {
private double radius;
Circle(double radius) {
    this.radius = radius;
}
@Override double area() {
    return Math.PI * radius * radius;
}
} final class Rectangle extends Shape {
private double width, height;
Rectangle(double width, double height) {
    this.width = width;
    this.height = height;
}
@Override double area() {
    return width * height;
}
} non-sealed class Triangle extends Shape {
private double base, height;
Triangle(double base, double height) {
    this.base = base;
    this.height = height;
}
@Override double area() {
    return 0.5 * base * height;
}
} // Triangle can be extended further class RightTriangle extends Triangle {
RightTriangle(double base, double height) {
    super(base, height);
}
}

4.2 Sealed Class Modifiers

  • final: Cannot be extended
  • sealed: Can only be extended by permitted classes
  • non-sealed: Can be extended by any class

5. Record Classes and Inheritance

Records can implement interfaces but cannot extend classes (except implicitly extending Record).

Example:
// Record implementing interface interface Drawable {
    void draw();
}
record Point(int x, int y) implements Drawable {
    @Override public void draw() {
        System.out.println("Drawing point at (" + x +"," + y +")");
    }
} // Record cannot extend class // class Base {
} // record Point(int x, int y) extends Base {
} // Compilation error // Sealed interface with records sealed interface Shape permits Circle, Rectangle {
double area();
}
record Circle(double radius) implements Shape {
    @Override public double area() {
        return Math.PI * radius * radius;
    }
} record Rectangle(double width, double height) implements Shape {
@Override public double area() {
    return width * height;
}
}

6. Object Class Methods

All classes inherit from Object class, which provides several important methods.

6.1 Important Object Methods

Method Description
equals(Object obj) Compares objects for equality
hashCode() Returns hash code
toString() Returns string representation
getClass() Returns Class object
clone() Creates a copy (protected)
finalize() Called before GC (deprecated)

6.2 Overriding Object Methods

Example:
class Person {
    private String name;
    private int age;
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
@Override public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass()) return false;
    Person person = (Person) obj;
    return age == person.age && Objects.equals(name, person.name);
}
@Override public int hashCode() {
    return Objects.hash(name, age);
}
@Override public String toString() {
    return"Person{name='" + name +"', age=" + age +"}";
}
}
Important: If you override equals() , you should also override hashCode() to maintain the contract: equal objects must have equal hash codes.

7. Polymorphism

Polymorphism allows objects of different types to be treated as objects of a common supertype.

7.1 Object Type vs Reference Type

Example:
class Animal {
    void makeSound() {
        System.out.println("Some sound");
    }
} class Dog extends Animal {
@Override void makeSound() {
    System.out.println("Woof!");
}
void fetch() {
    System.out.println("Fetching...");
}
} // Reference type: Animal, Object type: Dog Animal animal = new Dog();
animal.makeSound();
//"Woof!" (uses object type - Dog) // animal.fetch();
// Compilation error (reference type is Animal) // To call Dog-specific methods, need to cast if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    dog.fetch();
}

7.2 Runtime Polymorphism

Method calls are resolved at runtime based on the actual object type (dynamic method dispatch).

Example:
Animal[] animals = {new Dog(), new Cat(), new Bird()};
for (Animal animal : animals) {
    animal.makeSound();
    // Calls appropriate overridden method // Output depends on actual object type
}

8. Type Casting

Type casting converts a reference from one type to another.

8.1 Upcasting and Downcasting

Example:
class Animal {
}
class Dog extends Animal {
} // Upcasting (implicit, safe) Dog dog = new Dog();
Animal animal = dog;
// Automatic upcast // Downcasting (explicit, may throw ClassCastException) Animal animal2 = new Dog();
Dog dog2 = (Dog) animal2;
// Explicit cast required // Unsafe downcast Animal animal3 = new Animal();
// Dog dog3 = (Dog) animal3;
// ClassCastException at runtime // Safe downcast with instanceof check if (animal3 instanceof Dog) {
    Dog dog3 = (Dog) animal3;
}

9. instanceof and Pattern Matching

The instanceof operator checks if an object is an instance of a specific type. Pattern matching (Java 16+) simplifies this.

9.1 Traditional instanceof

Example:
Object obj ="Hello";
if (obj instanceof String) {
    String str = (String) obj;
    // Explicit cast needed System.out.println(str.toUpperCase());
}

9.2 Pattern Matching with instanceof

Example:
Object obj ="Hello";
// Pattern matching (Java 16+) - automatic cast if (obj instanceof String str) {
    System.out.println(str.toUpperCase());
    // No explicit cast needed } // Pattern matching in switch (Java 17+) Object value = 42;
String result = switch (value) {
    case String s ->"String:" + s;
    case Integer i ->"Integer:" + i;
    case null ->"Null";
    default ->"Unknown";
};
// Pattern matching with guards Object obj2 ="Hello";
if (obj2 instanceof String s && s.length() > 5) {
    System.out.println("Long string:" + s);
}

10. Exam Key Points

Critical Concepts for OCP 21 Exam:

  • Inheritance: extends keyword, single inheritance only
  • Method Overriding: Same signature, covariant return type, @Override annotation
  • super Keyword: Access parent class members, call parent constructor
  • Abstract Classes: Cannot be instantiated, can have abstract and concrete methods
  • Sealed Classes: Restrict inheritance to permitted classes (Java 17+)
  • Sealed Modifiers: final, sealed, non-sealed
  • Records: Can implement interfaces, cannot extend classes
  • Object Class: All classes inherit from Object
  • equals() and hashCode(): Must override together, maintain contract
  • Polymorphism: Runtime method resolution based on object type
  • Object Type vs Reference Type: Methods called based on object type
  • Upcasting: Implicit, safe (subclass to superclass)
  • Downcasting: Explicit, may throw ClassCastException
  • instanceof: Checks object type, use before downcasting
  • Pattern Matching: instanceof with automatic variable binding (Java 16+)
  • Pattern Matching in Switch: Type patterns in switch expressions (Java 17+)
  • Method Hiding: Static methods are hidden, not overridden
  • Constructor Chaining: super() calls parent constructor

Post a Comment

0 Comments