Inheritance lets one class reuse the fields and methods of another, avoiding the need to rewrite shared behaviour in every related class. A child class automatically receives everything a parent class defines and can add its own extra behaviour on top.

A parent class

public class Animal {
  void eat() {
    System.out.println("Eating");
  }
}

A child class

public class Dog extends Animal {
  void bark() {
    System.out.println("Woof");
  }
}

The extends keyword establishes the relationship. A Dog object automatically has access to eat, inherited from Animal, in addition to its own bark method, without eat ever being written inside Dog itself.

Overriding a method

@Override
void eat() {
  System.out.println("Dog eats enthusiastically");
}

A child class can replace, or override, a parent method with its own version. Marking it with @Override is not strictly required but is strongly recommended, since it lets the compiler catch a typo in the method signature that would otherwise silently create an unrelated new method instead of overriding the intended one.

The super keyword

Sometimes a child class wants to add to the parent behaviour rather than fully replace it. The super keyword calls the parent version of a method from inside the overriding one:

@Override
void eat() {
  super.eat();
  System.out.println("...and wags its tail");
}

Polymorphism

Because a Dog is also an Animal, a variable declared as the parent type can point to a child object, and calling an overridden method automatically runs the child version:

Animal a = new Dog();
a.eat();  // runs Dog's overridden version

This is polymorphism: the same line of code, a.eat(), behaves differently depending on the actual object behind the reference, which becomes powerful once a list holds several different subclasses handled through their shared parent type.

Abstract classes

An abstract class can define a method with no body at all, forcing every subclass to supply its own implementation:

public abstract class Shape {
  abstract double area();
}

An abstract class cannot be instantiated directly with new; it exists purely as a shared base for concrete subclasses to build on.

When to use inheritance

Inheritance fits best when classes share a genuine is-a relationship, such as a Dog truly being an Animal. When the relationship is closer to has-a, such as a Car having an Engine rather than being one, composition, where one class simply holds a reference to another, usually leads to more flexible and less tightly coupled code than forcing an inheritance relationship that does not really fit.