Inheritance
The extends keyword lets one class use another class's fields and methods, without rewriting them.
This boosts code reuse — write the common stuff in the parent, the specific stuff in the child.
class Animal {
void eat() { System.out.println("Eating..."); }
}
class Dog extends Animal {
void bark() { System.out.println("Woof!"); }
}- extends gives you the parent's features
- Boosts code reuse
- A child can add its own new things too
Single: a class extends just one parent (Dog extends Animal) — the most common type.
Multilevel: forms a chain (Puppy extends Dog extends Animal) — Puppy gets Dog's features and Animal's too (transitively).
Hierarchical: one parent has multiple children (Dog and Cat both extend Animal) — both get Animal's common behavior, but also have their own specific behavior.
Multiple inheritance (a class extending two classes, like class C extends A, B) is NOT allowed for Java classes — to avoid the "diamond problem" (if A and B both have a method with the same name, C wouldn't know which one to use). This is partially achieved through interfaces (a class can implement multiple interfaces).
| Type | Example |
|---|---|
| Single | Dog extends Animal |
| Multilevel | Puppy extends Dog extends Animal |
| Hierarchical | Dog extends Animal, Cat extends Animal |
| Multiple (classes) | NOT allowed in Java |
super.method() calls the parent class's overridden method (from inside the child) — useful when the child wants to *extend* the parent's behavior, not replace it. super.field accesses the parent's field, if the child has a field with the same name (variable "shadowing"). super(...) calls the parent constructor.
class Dog extends Animal {
void makeSound() {
super.makeSound(); // pehle parent ka version chalao
System.out.println("Woof!"); // fir apna add karo
}
}For overriding, the method signature (name + parameters, same order/types) must match exactly between parent and child. The return type can be the same, or "covariant" (a subtype).
Adding @Override is best practice — the compiler checks that you're truly overriding something (a typo would give a compile error, which is far better than a silent bug).
The access modifier in the child can't be more restrictive than the parent's — you can't turn a public method into protected while overriding it (this is the "visibility can widen, not narrow" rule).
When a child class's object is created, the parent class's constructor runs first (implicitly, or explicitly via super()), then the child's constructor. This guarantees the parent's setup is complete before the child builds on top of it.
This chain goes all the way to the root — with 3-level inheritance (A -> B -> C), the order when an object is created is: A's constructor, then B's, then C's.