JavaBook
Chapter 16· Object-Oriented Programming

Inheritance

61 min read26 diagrams

Java Master Course — Chapter 16 of 50

Inheritance is one of the major concepts of Object-Oriented Programming.

The basic idea is:

A new class can reuse and extend the features of an existing class.

Java uses the extends keyword for class inheritance.

This chapter explains inheritance deeply: parent and child classes, IS-A relationships, inheritance types, constructors, super, inherited members, access modifiers, overriding previews, polymorphism connections, composition vs inheritance, and practical design.


1. What Is Inheritance?#

Inheritance is an OOP mechanism in which one class derives from another class.

Java
class Animal {
    void eat() {
        System.out.println("Animal eats");
    }
}

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

Here:

Animal
   ↑
   |
  Dog

Animal is the parent/superclass.

Dog is the child/subclass.

Because Dog extends Animal, a Dog can use accessible inherited members of Animal.


2. Simple Definition#

Exam-friendly definition:

Inheritance is a mechanism in Java in which a subclass derives from a superclass and can reuse accessible members while adding or specializing its own behavior.

The keyword used for class inheritance is:

Java
extends

3. Basic Syntax#

Java
class Parent {
    // fields
    // methods
}

class Child extends Parent {
    // additional fields
    // additional methods
}

Example:

Java
class Vehicle {

    void start() {
        System.out.println("Vehicle starts");
    }
}

class Car extends Vehicle {

    void drive() {
        System.out.println("Car drives");
    }
}

4. Using the Child#

Java
Car car = new Car();

car.start();
car.drive();

Output:

Output
Vehicle starts
Car drives

start() comes from the superclass.

drive() belongs to Car.


5. Why Is Inheritance Used?#

Inheritance can provide:

Output
code reuse
common behavior
common type
specialization
polymorphism
hierarchical organization

But inheritance should not be used merely to avoid writing duplicate code.

It should represent a meaningful relationship.


6. Inheritance Is More Than Code Reuse#

Suppose:

Output
Dog extends Animal

This means more than:

Output
Dog can use Animal's code

It also means:

Output
Dog is an Animal

This is called an:

Output
IS-A relationship

7. IS-A Relationship#

Examples:

Output
Dog IS-A Animal
Cat IS-A Animal
Car IS-A Vehicle
Manager IS-A Employee
Student IS-A Person
Circle IS-A Shape

The child should genuinely represent a specialized form of the parent.


8. Parent Class Terminology#

The superclass may also be called:

Output
parent class
base class
superclass

Example:

Java
class Animal {
}

In:

Java
class Dog extends Animal {
}

Animal is the superclass.


9. Child Class Terminology#

The subclass may also be called:

Output
child class
derived class
subclass

Example:

Java
class Dog extends Animal {
}

Dog is the subclass.


10. First Complete Example#

Java
class Animal {

    void eat() {
        System.out.println("Animal eats");
    }

    void sleep() {
        System.out.println("Animal sleeps");
    }
}

class Dog extends Animal {

    void bark() {
        System.out.println("Dog barks");
    }
}

public class Main {

    public static void main(String[] args) {

        Dog dog = new Dog();

        dog.eat();
        dog.sleep();
        dog.bark();
    }
}

Output:

Output
Animal eats
Animal sleeps
Dog barks

11. What Happened Here?#

Animal defines:

Java
eat()
sleep()

Dog defines:

Java
bark()

Dog extends Animal.

Therefore a Dog object can use the accessible inherited methods:

Output
eat()
sleep()

and its own method:

Output
bark()

12. Inheritance Is Not Copy-Paste#

Do not imagine:

Animal source code
        ↓
copy
        ↓
Dog source code

Inheritance establishes a class hierarchy.

Java uses:

Output
class relationships
+
inheritance rules
+
access rules
+
method dispatch

It is not simply textual duplication of source code.


13. Single Inheritance#

Java supports single inheritance for classes.

A class has only one direct superclass.

Valid:

Java
class Dog extends Animal {
}

Invalid:

Java
class Dog extends Animal, Pet {
}

A class cannot directly extend two classes.


14. Single Inheritance Diagram#

Animal
  ↑
 Dog

Dog has one direct superclass:

Output
Animal

15. Multilevel Inheritance#

Multilevel inheritance occurs when inheritance continues through multiple levels.

Example:

Java
class Animal {
}

class Mammal extends Animal {
}

class Dog extends Mammal {
}

Diagram:

Animal
   ↑
Mammal
   ↑
 Dog

Dog indirectly derives from Animal.


16. Multilevel Example#

Java
class Animal {

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

class Mammal extends Animal {

    void walk() {
        System.out.println("Walking");
    }
}

class Dog extends Mammal {

    void bark() {
        System.out.println("Barking");
    }
}

Usage:

Java
Dog dog = new Dog();

dog.eat();
dog.walk();
dog.bark();

Output:

Output
Eating
Walking
Barking

17. Why Does Dog Get eat()?#

The hierarchy is:

Dog
 ↓
Mammal
 ↓
Animal

Java can find inherited accessible members through the superclass chain.

Therefore Dog can use the inherited eat() method.


18. Hierarchical Inheritance#

Hierarchical inheritance means multiple subclasses share one superclass.

Example:

Output
          Animal
        /    |    \
       /     |     \
     Dog    Cat    Cow

Java supports this pattern.


19. Hierarchical Example#

Java
class Animal {

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

class Dog extends Animal {

    void bark() {
        System.out.println("Barking");
    }
}

class Cat extends Animal {

    void meow() {
        System.out.println("Meowing");
    }
}

class Cow extends Animal {

    void moo() {
        System.out.println("Mooing");
    }
}

20. Using Hierarchical Classes#

Java
Dog dog = new Dog();
Cat cat = new Cat();
Cow cow = new Cow();

dog.eat();
dog.bark();

cat.eat();
cat.meow();

cow.eat();
cow.moo();

Common behavior:

Output
eat()

comes from Animal.


21. Multiple Inheritance of Classes#

Java does not support:

Java
class C extends A, B {
}

This is a compile-time error.

A Java class has one direct superclass.


22. Why Does Java Avoid Multiple Class Inheritance?#

One major reason is ambiguity.

Imagine:

Output
       A
      / \
     B   C
      \ /
       D

Suppose A defines:

Java
void show()

and both B and C provide different implementations.

If D inherited from both B and C, which show() should D use?

This is related to the classic diamond problem.

Java avoids this kind of class-level ambiguity by allowing one direct superclass.

Interfaces provide another way to obtain multiple types and are covered later.


23. Multiple Interfaces#

Although a class cannot extend multiple classes, it can implement multiple interfaces.

Example:

Java
class Dog
    extends Animal
    implements Runnable, Comparable<Dog> {
}

This distinction is important:

Output
extends
→ one class

implements
→ multiple interfaces possible

Interfaces are covered in Chapter 21.


24. IS-A vs HAS-A#

This is one of the most important inheritance design tests.

Output
IS-A
→ usually inheritance

HAS-A
→ usually composition/association

Example:

Output
Dog IS-A Animal
Car HAS-A Engine

25. Car and Engine#

Incorrect:

Java
class Car extends Engine {
}

A car is not an engine.

Better:

Java
class Car {

    private Engine engine;
}

Now:

Output
Car HAS-A Engine

26. Why This Distinction Matters#

Inheritance says:

Output
this object is a specialized form of that type

Composition says:

Output
this object contains/uses another object

They represent different relationships.


27. Parent and Child Responsibilities#

A parent should normally contain:

Output
common state
common behavior
common contract

A child should contain:

Output
specialized state
specialized behavior
specialized implementation

Example:

Diagram
Employee
├── id
├── name
└── work()

Developer
└── writeCode()

Manager
└── manageTeam()

28. Example — Employee Hierarchy#

Java
class Employee {

    private final int id;
    private final String name;

    Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void work() {
        System.out.println(
            name + " is working"
        );
    }
}

class Developer extends Employee {

    Developer(int id, String name) {
        super(id, name);
    }

    public void writeCode() {
        System.out.println(
            getName() + " writes code"
        );
    }
}

class Manager extends Employee {

    Manager(int id, String name) {
        super(id, name);
    }

    public void manageTeam() {
        System.out.println(
            getName() + " manages team"
        );
    }
}

29. Using Employee Subclasses#

Java
Developer developer =
    new Developer(101, "Aman");

Manager manager =
    new Manager(102, "Riya");

developer.work();
developer.writeCode();

manager.work();
manager.manageTeam();

Output:

Output
Aman is working
Aman writes code
Riya is working
Riya manages team

30. Constructors Are Not Inherited#

This is one of the most important rules.

If:

Java
class Animal {
    Animal() {
    }
}

and:

Java
class Dog extends Animal {
}

Dog does not inherit the Animal constructor.

Constructors belong to their own class.


31. But Parent Constructors Run#

When a child object is created:

Java
Dog dog = new Dog();

a superclass constructor executes as part of the construction process.

That does not mean the constructor was inherited.


32. Constructor Example#

Java
class Animal {

    Animal() {
        System.out.println(
            "Animal constructor"
        );
    }
}

class Dog extends Animal {

    Dog() {
        System.out.println(
            "Dog constructor"
        );
    }
}

Usage:

Java
new Dog();

Output:

Output
Animal constructor
Dog constructor

33. Why Does the Parent Constructor Run First?#

A subclass object has a superclass part that must be initialized.

Conceptually:

create Dog
    ↓
initialize superclass part
    ↓
Animal constructor
    ↓
initialize subclass part
    ↓
Dog constructor

This is a useful mental model.


34. super()#

The subclass constructor can explicitly call the superclass no-argument constructor:

Java
super();

Example:

Java
class Animal {

    Animal() {
        System.out.println("Animal");
    }
}

class Dog extends Animal {

    Dog() {
        super();
        System.out.println("Dog");
    }
}

35. Implicit super()#

If a constructor does not explicitly begin with a constructor invocation, Java may implicitly insert:

Java
super();

provided the superclass has an accessible no-argument constructor.

Example:

Java
class Dog extends Animal {

    Dog() {
        System.out.println("Dog");
    }
}

Conceptually, the constructor begins with:

Java
super();

if that call is valid.


36. Parent Without No-Argument Constructor#

Consider:

Java
class Animal {

    Animal(String name) {
        System.out.println(name);
    }
}

class Dog extends Animal {

    Dog() {
        System.out.println("Dog");
    }
}

This does not compile.

Why?

Because Java would need a no-argument superclass constructor for the implicit super() call, but Animal does not provide one.


37. Correct Solution#

Use:

Java
super("Dog");

Example:

Java
class Animal {

    Animal(String name) {
        System.out.println(
            "Animal: " + name
        );
    }
}

class Dog extends Animal {

    Dog() {
        super("Dog");

        System.out.println(
            "Dog constructor"
        );
    }
}

Output:

Output
Animal: Dog
Dog constructor

38. super(arguments)#

super(arguments) invokes a matching accessible constructor in the superclass.

Example:

Java
class Person {

    Person(String name) {
        System.out.println(
            "Person: " + name
        );
    }
}

class Student extends Person {

    Student(String name) {
        super(name);
    }
}

39. super(...) Must Be First#

A superclass constructor invocation must appear as the first statement in the constructor.

Valid:

Java
Student(String name) {
    super(name);
    System.out.println("Student");
}

Invalid:

Java
Student(String name) {
    System.out.println("Before");
    super(name);
}

40. this() vs super()#

Remember:

Output
this(...)
→ another constructor in the same class

super(...)
→ constructor in the superclass

A constructor invocation must be first.

You cannot write:

Java
this(...);
super(...);

in the same constructor.


41. Constructor Chaining#

You can chain child constructors and then invoke a parent constructor.

Example:

Java
class Person {

    Person(String name) {
        System.out.println(
            "Person: " + name
        );
    }
}

class Student extends Person {

    Student() {
        this("Unknown");
    }

    Student(String name) {
        super(name);

        System.out.println(
            "Student: " + name
        );
    }
}

Usage:

Java
new Student();

Output:

Output
Person: Unknown
Student: Unknown

42. Constructor Execution in Three Levels#

Java
class A {

    A() {
        System.out.println("A");
    }
}

class B extends A {

    B() {
        System.out.println("B");
    }
}

class C extends B {

    C() {
        System.out.println("C");
    }
}

Then:

Java
new C();

Output:

Output
A
B
C

43. Constructor Order Rule#

For a child object:

superclass constructor
        ↓
parent constructor
        ↓
child constructor

For multiple inheritance levels:

highest superclass
        ↓
next superclass
        ↓
child

44. super Keyword#

super is used to refer to superclass context from a subclass.

Common uses:

Output
super()
super(arguments)
super.field
super.method()

45. super.field#

Example:

Java
class Parent {

    int value = 10;
}

class Child extends Parent {

    int value = 20;

    void show() {
        System.out.println(value);
        System.out.println(super.value);
    }
}

Output:

Output
20
10

46. Why Does This Happen?#

Inside Child:

Java
value

refers to the Child field.

While:

Java
super.value

explicitly refers to the Parent field.


47. Fields Are Not Overridden#

This is a critical distinction.

Methods can be overridden.

Fields are not overridden.

Example:

Java
class Parent {
    int x = 10;
}

class Child extends Parent {
    int x = 20;
}

There are two fields:

Output
Parent.x
Child.x

This is field hiding.


48. Field Hiding Example#

Java
class Parent {

    int x = 10;
}

class Child extends Parent {

    int x = 20;

    void show() {
        System.out.println(x);
        System.out.println(super.x);
    }
}

Output:

Output
20
10

49. Avoid Unnecessary Field Hiding#

This can confuse readers.

Instead of:

Java
int value;

in both classes, use clear names or keep state private and expose appropriate methods.


50. super.method()#

A subclass can explicitly invoke a superclass instance method:

Java
super.method();

Example:

Java
class Animal {

    void sound() {
        System.out.println(
            "Animal sound"
        );
    }
}

class Dog extends Animal {

    @Override
    void sound() {
        System.out.println(
            "Dog sound"
        );

        super.sound();
    }
}

Output:

Output
Dog sound
Animal sound

51. Why Use super.method()?#

It is useful when the child wants to extend the parent's behavior.

Example:

Java
class Employee {

    void work() {
        System.out.println(
            "Employee works"
        );
    }
}

class Manager extends Employee {

    @Override
    void work() {
        super.work();

        System.out.println(
            "Manager manages"
        );
    }
}

52. Method Inheritance#

If a child does not provide its own implementation of an accessible inherited method, it can use the superclass implementation.

Example:

Java
class Animal {

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

class Dog extends Animal {
}

Then:

Java
Dog dog = new Dog();

dog.eat();

Output:

Output
Eating

53. Method Overriding Preview#

A subclass can provide a specialized implementation of an inherited instance method.

Example:

Java
class Animal {

    void sound() {
        System.out.println(
            "Generic sound"
        );
    }
}

class Dog extends Animal {

    @Override
    void sound() {
        System.out.println(
            "Bark"
        );
    }
}

This is method overriding.

A complete discussion appears in Chapter 18.


54. @Override#

When overriding a method, use:

Java
@Override

Example:

Java
@Override
void sound() {
    System.out.println("Bark");
}

The compiler checks that the method actually overrides an inherited method.

This helps catch mistakes.


55. Example of a Useful @Override#

Suppose the parent method is:

Java
void sound()

but you accidentally write:

Java
void sounds()

Without @Override, the compiler may treat it as a new method.

With:

Java
@Override
void sounds()

the compiler reports an error because sounds() does not override the parent method.


56. Parent Method Can Still Be Called#

If a child overrides:

Java
sound()

the parent implementation can be explicitly called with:

Java
super.sound();

This allows:

Output
parent behavior
+
child behavior

57. Inheritance and Access Modifiers#

Inheritance does not bypass access control.

Java has:

Output
private
package-private
protected
public

These determine accessibility.


58. Private Parent Field#

Example:

Java
class Parent {

    private int value = 10;
}

class Child extends Parent {

    void show() {
        // System.out.println(value);
    }
}

The direct access is invalid because value is private.


59. Private Does Not Mean Parent State Disappears#

The superclass state can still be part of the object.

But the subclass cannot directly access the parent's private member.

The parent class controls its private implementation.


60. Access Through Parent Method#

Java
class Parent {

    private int value = 10;

    public int getValue() {
        return value;
    }
}

class Child extends Parent {

    void show() {
        System.out.println(
            getValue()
        );
    }
}

Child uses the parent's public method.


61. Protected#

protected is often used in inheritance examples.

Java
class Parent {

    protected int value = 10;
}

class Child extends Parent {

    void show() {
        System.out.println(value);
    }
}

Detailed package and cross-package behavior is covered in Chapter 24.


62. Public#

Public members are accessible wherever Java's access rules allow public access.

Example:

Java
class Parent {

    public void show() {
        System.out.println("Parent");
    }
}

class Child extends Parent {
}

Usage:

Java
Child c = new Child();

c.show();

63. Package-Private#

If no modifier is specified:

Java
class Parent {

    void show() {
    }
}

the member has package-private access.

This means access is available within the same package.

Inheritance across package boundaries introduces additional rules.


64. Why Prefer Private Fields?#

Instead of:

Java
class Employee {
    protected double salary;
}

often prefer:

Java
class Employee {

    private double salary;

    protected double getSalary() {
        return salary;
    }
}

This gives the superclass greater control over its internal representation.


65. Encapsulation and Inheritance#

Inheritance does not mean:

Output
all parent fields become freely accessible

Encapsulation still matters.

A well-designed parent can keep:

Java
private

fields and provide controlled methods.


66. Example — Encapsulated Parent#

Java
class Employee {

    private double salary;

    Employee(double salary) {
        if (salary < 0) {
            throw new IllegalArgumentException();
        }

        this.salary = salary;
    }

    protected final double getSalary() {
        return salary;
    }

    protected final void increaseSalary(
        double amount
    ) {
        if (amount < 0) {
            throw new IllegalArgumentException();
        }

        salary += amount;
    }
}

A subclass can use controlled operations without directly changing the field.


67. Inheritance and Static Members#

Static members belong to classes rather than representing dynamically dispatched object behavior.

A subclass can often access inherited static members according to normal access rules.

Example:

Java
class Parent {

    static int count = 10;
}

class Child extends Parent {
}

Then:

Java
System.out.println(Child.count);

can access the inherited static member.

But the member is still class-oriented.


68. Static Fields Are Not Per-Object Copies#

If:

Java
class Parent {
    static int count = 10;
}

and:

Java
class Child extends Parent {
}

creating many Child objects does not create a separate count for every object.

The static field belongs to the declaring class.


69. Static Method Hiding#

Suppose:

Java
class Parent {

    static void show() {
        System.out.println("Parent");
    }
}

class Child extends Parent {

    static void show() {
        System.out.println("Child");
    }
}

The Child method hides the Parent static method.

This is not method overriding.


70. Why Static Methods Are Not Overridden#

Runtime overriding applies to instance methods.

Static methods are associated with class members.

Therefore:

Output
instance method
→ can be overridden

static method
→ can be hidden

71. Final Class#

A class can be declared:

Java
final

Example:

Java
final class Animal {
}

It cannot be extended.

This is useful when a class should not have subclasses.


72. Attempting to Extend Final Class#

Java
final class Animal {
}

class Dog extends Animal {
}

This causes a compilation error.


73. Final Method#

A method can also be final:

Java
class Parent {

    final void show() {
        System.out.println("Parent");
    }
}

A child cannot override it.


74. Why Use a Final Method?#

A final method can guarantee that subclasses cannot replace a particular implementation.

Example:

Java
class Account {

    final void audit() {
        System.out.println(
            "Audit logic"
        );
    }
}

A subclass cannot override audit().


75. Access Level and Overriding#

Suppose:

Java
class Parent {

    public void show() {
    }
}

A child cannot override it with:

Java
protected void show() {
}

because this reduces accessibility.


76. Increasing Access Is Allowed#

Suppose parent:

Java
protected void show()

The child may override:

Java
public void show()

because access becomes broader.


77. Private Methods and Overriding#

A private method is not inherited in the way required for overriding.

Example:

Java
class Parent {

    private void show() {
    }
}

A child declaring:

Java
class Child extends Parent {

    private void show() {
    }
}

has its own method.

It is not an override of Parent's private method.


78. Constructors and Private Constructors#

A private constructor can prevent normal construction from outside the class.

Inheritance is also affected because a subclass constructor must be able to invoke an accessible superclass constructor.

Example:

Java
class Parent {

    private Parent() {
    }
}

class Child extends Parent {
}

This cannot compile because Child cannot invoke the private Parent constructor.


79. Object Class#

Every Java class ultimately derives from:

Java
java.lang.Object

The hierarchy may look like:

Object
   ↑
Animal
   ↑
Dog

Object is the root superclass of ordinary Java class hierarchies.


80. Common Object Methods#

Object provides methods such as:

Output
toString()
equals()
hashCode()
getClass()

among others.

These are important in Java programming and are covered more deeply later.


81. Example with getClass()#

Java
class Animal {
}

class Dog extends Animal {
}

Dog dog = new Dog();

System.out.println(
    dog.getClass().getSimpleName()
);

Output:

Output
Dog

82. Example with toString()#

Java
class Student {

    private final String name;

    Student(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{name='" +
               name + "'}";
    }
}

The child class can override inherited Object behavior.


83. Upcasting#

Because a subclass is a subtype of its superclass:

Java
Dog dog = new Dog();

Animal animal = dog;

This is called upcasting.

It can also be written:

Java
Animal animal = new Dog();

84. Why Is Upcasting Safe?#

Because:

Output
Dog IS-A Animal

Every Dog is an Animal in this model.

So a Dog reference can be treated as an Animal reference.


85. Reference Type vs Object Type#

For:

Java
Animal animal = new Dog();

remember:

Output
declared/reference type → Animal
actual object type       → Dog

This distinction is critical.


86. What Can an Animal Reference Access?#

Suppose:

Java
class Animal {

    void eat() {
    }
}

class Dog extends Animal {

    void bark() {
    }
}

Then:

Java
Animal a = new Dog();

a.eat();

is valid.

But:

Java
a.bark();

does not compile because bark() is not part of the Animal reference type.


87. Why Is bark() Not Available?#

The compiler sees:

Java
Animal a

So it checks the members available through Animal.

Even though the actual object is a Dog, the variable's compile-time type controls which members can be directly selected.


88. Runtime Dispatch Preview#

Now consider:

Java
Animal a = new Dog();

a.sound();

If Dog overrides sound(), Java can select the Dog implementation at runtime.

Example:

Java
class Animal {

    void sound() {
        System.out.println("Animal");
    }
}

class Dog extends Animal {

    @Override
    void sound() {
        System.out.println("Dog");
    }
}

Then:

Java
Animal a = new Dog();

a.sound();

Output:

Output
Dog

This is runtime polymorphism.


89. Downcasting#

Suppose:

Java
Animal animal = new Dog();

If you know the actual object is a Dog, you can cast:

Java
Dog dog = (Dog) animal;

This is downcasting.


90. Unsafe Downcasting#

Consider:

Java
Animal animal = new Cat();

Dog dog = (Dog) animal;

The actual object is Cat, not Dog.

The cast fails at runtime with:

Output
ClassCastException

91. instanceof#

You can check the object's compatibility before downcasting.

Example:

Java
Animal animal = new Dog();

if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    dog.bark();
}

Modern Java also provides pattern matching for instanceof; that is covered later.


92. Inheritance and Arrays#

A parent-type array can hold subclass objects.

Example:

Java
Animal[] animals = {
    new Dog(),
    new Cat()
};

Each element is an Animal reference.

The actual objects are:

Output
Dog
Cat

93. Inheritance and Collections#

Similarly:

Java
List<Animal> animals =
    new ArrayList<>();

animals.add(new Dog());
animals.add(new Cat());

A collection typed as Animal can hold compatible subtype objects.

Generics and collections are covered later.


94. Generic Method with Parent Type#

Example:

Java
static void feed(Animal animal) {
    animal.eat();
}

Now:

Java
feed(new Dog());
feed(new Cat());

Both are valid because both are Animals.


95. Why This Is Powerful#

Instead of writing:

Java
feedDog()
feedCat()
feedCow()

you can write:

Java
feed(Animal animal)

and let the type hierarchy handle compatible objects.

This becomes even more powerful when methods are overridden.


96. Inheritance and Polymorphism#

Inheritance creates the subtype relationship.

Polymorphism allows code to work with a general type while the actual object can provide specialized behavior.

Example:

Java
Animal animal = new Dog();

animal.sound();

The Animal reference can refer to a Dog object.


97. Inheritance and Abstraction#

Inheritance is also commonly used with abstraction.

Example:

Shape
├── Circle
├── Rectangle
└── Triangle

The parent can describe common shape behavior.

Subclasses can provide specialized implementations.

Abstract classes are covered in Chapter 20.


98. Inheritance and Encapsulation#

A parent class can protect its internal data:

Java
class Account {

    private double balance;
}

and expose controlled operations:

Java
deposit()
withdraw()

A subclass does not automatically gain direct access to the private field.


99. Inheritance Should Preserve Meaning#

If:

Output
Dog IS-A Animal

then code that expects an Animal should generally be able to work with Dog according to the Animal contract.

This idea is connected to the Liskov Substitution Principle.

It is discussed more deeply in Chapter 23.


100. Example of a Problematic Hierarchy#

Consider:

Rectangle
   ↑
 Square

At first glance:

Output
Square IS-A Rectangle

is mathematically true.

But suppose Rectangle allows:

Java
setWidth()
setHeight()

independently.

A Square must maintain:

Output
width == height

This can create behavioral conflicts.

The lesson:

Inheritance should be evaluated by behavior and contract, not just by vocabulary.


101. Inheritance vs Composition#

Inheritance:

Output
Dog IS-A Animal

Composition:

Output
Car HAS-A Engine

Example:

Java
class Car {

    private Engine engine;
}

102. Why Composition Is Often Flexible#

Inheritance creates a strong connection between subclass and superclass.

Composition allows objects to collaborate without making one object a subtype of another.

Example:

Java
class Car {

    private Engine engine;

    Car(Engine engine) {
        this.engine = engine;
    }

    void start() {
        engine.start();
    }
}

103. Composition Example#

Java
class Engine {

    void start() {
        System.out.println(
            "Engine starts"
        );
    }
}

class Car {

    private final Engine engine;

    Car(Engine engine) {
        this.engine = engine;
    }

    void start() {
        engine.start();

        System.out.println(
            "Car starts"
        );
    }
}

This is a HAS-A relationship.


104. Do Not Use Inheritance for Reuse Alone#

Suppose:

Output
Class B needs one utility method from Class A

That does not automatically mean:

Java
class B extends A

Ask:

Output
Is B genuinely an A?

If not, use composition, a utility, delegation, or another suitable design.


105. Common Mistake — Everything Extends Something Custom#

Beginners sometimes create:

BaseClass
  ↑
Every class

without meaningful shared behavior.

This can make the design more complicated rather than simpler.


106. Common Mistake — Deep Inheritance#

Example:

A
↑
B
↑
C
↑
D
↑
E
↑
F

Deep hierarchies can make behavior difficult to understand.

Prefer shallow, meaningful hierarchies when possible.


107. Common Mistake — Protected Fields Everywhere#

Avoid automatically writing:

Java
protected int x;
protected String name;
protected double salary;

for every parent field.

Subclasses then become tightly coupled to parent representation.

Private fields plus controlled methods often provide better encapsulation.


108. Common Mistake — Forgetting super(...)#

If the parent has:

Java
Parent(String name)

then the child must invoke an accessible matching constructor:

Java
Child(String name) {
    super(name);
}

when no suitable no-argument constructor exists.


109. Common Mistake — Thinking Constructors Are Inherited#

Constructors are not inherited.

The child defines its own constructors.

Those constructors can invoke superclass constructors with:

Java
super(...)

110. Common Mistake — Confusing Overloading and Overriding#

Overloading:

Java
void show()
void show(int x)

Same name, different parameter lists.

Overriding:

Java
class Parent {
    void show() {}
}

class Child extends Parent {
    @Override
    void show() {}
}

Same inherited instance method signature, specialized child implementation.


111. Common Mistake — Thinking Fields Override#

Fields do not participate in dynamic overriding.

Example:

Java
class Parent {
    int x = 10;
}

class Child extends Parent {
    int x = 20;
}

This is field hiding.


112. Common Mistake — Parent Reference Means Parent Object#

This:

Java
Animal a = new Dog();

creates a Dog object.

It does not create an Animal object and convert it into Dog.

The reference variable has type Animal.

The actual object is Dog.


113. Common Mistake — Assuming Parent Reference Can Call Child Methods#

Given:

Java
Animal a = new Dog();

this does not automatically allow:

Java
a.bark();

if bark() is only declared in Dog.

The declared type controls direct member access.


114. Common Mistake — Unsafe Downcasting#

Avoid blindly writing:

Java
Dog d = (Dog) animal;

unless the object is known to be a Dog.

Use instanceof when necessary.


115. Common Mistake — Using super in Static Context#

super is associated with an instance context.

You cannot use:

Java
super

from a static method.

Static methods do not have a current object represented by this.


116. Common Mistake — Calling super() Anywhere#

super() is a constructor invocation.

It can only be used as a constructor invocation in a constructor.

You cannot write:

Java
void method() {
    super();
}

117. Common Mistake — Calling Parent Constructor Like a Method#

This is invalid:

Java
void test() {
    Parent();
}

Constructors are not normal methods.

Use:

Java
super(...);

inside a subclass constructor.


118. Practical Program — Person and Student#

Java
class Person {

    private final String name;
    private final int age;

    Person(String name, int age) {
        if (name == null || name.isBlank()) {
            throw new IllegalArgumentException();
        }

        if (age < 0) {
            throw new IllegalArgumentException();
        }

        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

class Student extends Person {

    private final int rollNumber;

    Student(
        String name,
        int age,
        int rollNumber
    ) {
        super(name, age);
        this.rollNumber = rollNumber;
    }

    public int getRollNumber() {
        return rollNumber;
    }
}

119. Student Usage#

Java
Student student =
    new Student("Aman", 20, 101);

System.out.println(
    student.getName()
);

System.out.println(
    student.getAge()
);

System.out.println(
    student.getRollNumber()
);

Output:

Output
Aman
20
101

120. What Does Student Reuse?#

Student uses inherited:

Java
getName()
getAge()

from Person.

Student adds:

Java
rollNumber
getRollNumber()

121. Practical Program — Vehicle#

Java
class Vehicle {

    private final String brand;

    Vehicle(String brand) {
        if (brand == null || brand.isBlank()) {
            throw new IllegalArgumentException();
        }

        this.brand = brand;
    }

    public String getBrand() {
        return brand;
    }

    public void start() {
        System.out.println(
            brand + " starts"
        );
    }

    public void stop() {
        System.out.println(
            brand + " stops"
        );
    }
}

class Car extends Vehicle {

    Car(String brand) {
        super(brand);
    }

    public void drive() {
        System.out.println(
            getBrand() + " drives"
        );
    }
}

class Bike extends Vehicle {

    Bike(String brand) {
        super(brand);
    }

    public void ride() {
        System.out.println(
            getBrand() + " rides"
        );
    }
}

122. Vehicle Usage#

Java
Car car = new Car("Toyota");
Bike bike = new Bike("Honda");

car.start();
car.drive();
car.stop();

bike.start();
bike.ride();
bike.stop();

Output:

Output
Toyota starts
Toyota drives
Toyota stops
Honda starts
Honda rides
Honda stops

123. Practical Program — Animal#

Java
class Animal {

    private final String name;

    Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void eat() {
        System.out.println(
            name + " eats"
        );
    }
}

class Dog extends Animal {

    Dog(String name) {
        super(name);
    }

    public void bark() {
        System.out.println(
            getName() + " barks"
        );
    }
}

class Cat extends Animal {

    Cat(String name) {
        super(name);
    }

    public void meow() {
        System.out.println(
            getName() + " meows"
        );
    }
}

124. Practical Program — Banking Hierarchy#

Java
class BankAccount {

    private final String accountNumber;
    private double balance;

    BankAccount(
        String accountNumber,
        double initialBalance
    ) {
        if (accountNumber == null ||
            accountNumber.isBlank()) {
            throw new IllegalArgumentException();
        }

        if (initialBalance < 0) {
            throw new IllegalArgumentException();
        }

        this.accountNumber = accountNumber;
        this.balance = initialBalance;
    }

    public String getAccountNumber() {
        return accountNumber;
    }

    public double getBalance() {
        return balance;
    }

    public void deposit(double amount) {
        if (amount <= 0) {
            throw new IllegalArgumentException();
        }

        balance += amount;
    }

    public void withdraw(double amount) {
        if (amount <= 0 ||
            amount > balance) {
            throw new IllegalArgumentException();
        }

        balance -= amount;
    }
}

class SavingsAccount extends BankAccount {

    SavingsAccount(
        String accountNumber,
        double balance
    ) {
        super(accountNumber, balance);
    }

    public void addInterest(double rate) {
        if (rate < 0) {
            throw new IllegalArgumentException();
        }

        double interest =
            getBalance() * rate / 100;

        deposit(interest);
    }
}

125. Why This Banking Design Is Better#

The parent owns:

Output
account number
balance
deposit
withdraw

The child adds:

Output
interest

The balance remains private.

The subclass uses public methods instead of directly changing parent state.


126. Practical Program — Employee Hierarchy#

Java
class Employee {

    private final int id;
    private final String name;

    Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void work() {
        System.out.println(
            name + " works"
        );
    }
}

class Developer extends Employee {

    Developer(int id, String name) {
        super(id, name);
    }

    public void writeCode() {
        System.out.println(
            getName() + " writes Java code"
        );
    }
}

class Manager extends Employee {

    Manager(int id, String name) {
        super(id, name);
    }

    public void manageTeam() {
        System.out.println(
            getName() + " manages the team"
        );
    }
}

127. Practical Program — Shape#

Java
class Shape {

    public void draw() {
        System.out.println(
            "Drawing shape"
        );
    }
}

class Circle extends Shape {

    @Override
    public void draw() {
        System.out.println(
            "Drawing circle"
        );
    }
}

class Rectangle extends Shape {

    @Override
    public void draw() {
        System.out.println(
            "Drawing rectangle"
        );
    }
}

128. Shape Usage#

Java
Shape circle = new Circle();
Shape rectangle = new Rectangle();

circle.draw();
rectangle.draw();

Output:

Output
Drawing circle
Drawing rectangle

This demonstrates inheritance plus runtime polymorphism.


129. Practical Program — Multilevel#

Java
class LivingThing {

    void breathe() {
        System.out.println("Breathing");
    }
}

class Animal extends LivingThing {

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

class Dog extends Animal {

    void bark() {
        System.out.println("Barking");
    }
}

Usage:

Java
Dog dog = new Dog();

dog.breathe();
dog.eat();
dog.bark();

Output:

Output
Breathing
Eating
Barking

130. Practical Program — super.method()#

Java
class Employee {

    public void work() {
        System.out.println(
            "Employee work"
        );
    }
}

class Manager extends Employee {

    @Override
    public void work() {
        super.work();

        System.out.println(
            "Manager planning"
        );
    }
}

Output:

Output
Employee work
Manager planning

131. Practical Program — Parent and Child Fields#

Java
class Parent {

    int value = 10;
}

class Child extends Parent {

    int value = 20;

    void show() {
        System.out.println(
            "Child: " + this.value
        );

        System.out.println(
            "Parent: " + super.value
        );
    }
}

Output:

Output
Child: 20
Parent: 10

Remember:

Output
this.value
→ Child field

super.value
→ Parent field

132. Practical Program — Upcasting#

Java
class Animal {

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

class Dog extends Animal {

    void bark() {
        System.out.println("Barking");
    }
}

public class Main {

    public static void main(String[] args) {

        Animal animal = new Dog();

        animal.eat();
    }
}

Output:

Output
Eating

133. Upcasting with Overriding#

Java
class Animal {

    void sound() {
        System.out.println("Animal");
    }
}

class Dog extends Animal {

    @Override
    void sound() {
        System.out.println("Dog");
    }
}

Animal animal = new Dog();

animal.sound();

Output:

Output
Dog

The actual object is Dog.


134. Practical Program — instanceof#

Java
Animal animal = new Dog();

if (animal instanceof Dog) {
    Dog dog = (Dog) animal;

    dog.bark();
}

Output:

Output
Barking

135. Practical Program — Parent Parameter#

Java
static void feed(Animal animal) {
    animal.eat();
}

Usage:

Java
feed(new Dog());
feed(new Cat());

Both objects can be passed because both are Animals.


136. Why Parent Parameters Are Useful#

A method such as:

Java
void feed(Animal animal)

is more general than:

Java
void feed(Dog dog)

when the method only requires behavior available from Animal.

This supports flexible polymorphic code.


137. Practical Program — Animal Array#

Java
Animal[] animals = {
    new Dog("Bruno"),
    new Cat("Milo")
};

Then:

Java
for (Animal animal : animals) {
    animal.eat();
}

Each array element is an Animal reference.

The actual objects are Dog and Cat.


138. Inheritance and Memory — Safe Mental Model#

When explaining inheritance and memory, avoid saying:

Output
parent object + child object are always two separate heap objects

That is not correct.

Creating:

Java
new Dog()

creates one object whose class is Dog.

That object is also an instance of its superclass types.

A useful conceptual model is:

Dog object
├── superclass state/behavior relationship
└── Dog-specific state/behavior

The exact physical memory layout is JVM implementation-specific.


139. One Object, Multiple Types#

For:

Java
Dog dog = new Dog();

the same object can be treated as:

Output
Dog
Animal
Object

because Dog is an Animal and every ordinary class ultimately derives from Object.


140. Type Hierarchy#

Example:

Object
   ↑
Animal
   ↑
Dog

A Dog object is compatible with all these reference types:

Java
Dog d = new Dog();

Animal a = d;

Object o = d;

141. Important Difference#

These are different:

Java
Dog d = new Dog();
Java
Animal a = new Dog();
Java
Object o = new Dog();

The actual object is Dog in all three cases.

Only the reference type changes.


142. Method Availability vs Runtime Behavior#

For:

Java
Animal a = new Dog();

two questions must be separated:

Output
What methods can the compiler let me call?
→ based on Animal reference type

Which overridden instance implementation executes?
→ based on runtime object

This distinction is fundamental to polymorphism.


143. Inheritance and super Example#

Java
class Animal {

    void sound() {
        System.out.println(
            "Generic animal sound"
        );
    }
}

class Dog extends Animal {

    @Override
    void sound() {
        System.out.println(
            "Dog sound"
        );

        super.sound();
    }
}

Here:

Output
sound()
→ Dog implementation

super.sound()
→ Animal implementation

144. Inheritance and Method Reuse#

A child can reuse parent behavior without overriding it.

Java
class Vehicle {

    void start() {
        System.out.println("Start");
    }
}

class Car extends Vehicle {
}

Then:

Java
new Car().start();

uses the inherited implementation.


145. Inheritance and Specialization#

A child can add functionality.

Java
class Vehicle {

    void start() {
    }
}

class Car extends Vehicle {

    void openTrunk() {
    }
}

This is specialization.


146. Inheritance and Overriding#

A child can replace an inherited instance method's implementation.

Java
class Vehicle {

    void start() {
        System.out.println("Vehicle");
    }
}

class ElectricCar extends Vehicle {

    @Override
    void start() {
        System.out.println(
            "Electric system starts"
        );
    }
}

This is specialization through overriding.


147. Inheritance and Extension#

A subclass can combine:

Output
inherited behavior
+
new behavior
+
overridden behavior

Example:

Diagram
Employee
   ↓
Manager

inherited:
work()

new:
manageTeam()

overridden:
work()

148. Good Parent Class#

A good parent often has:

Output
highly relevant common behavior
stable concepts
clear contract
appropriate abstraction level

149. Bad Parent Class#

A poor parent may have:

Output
unrelated methods
too many responsibilities
implementation details children should not know
unstable APIs

This can make every subclass unnecessarily complicated.


150. Inheritance and Coupling#

Inheritance creates strong coupling between parent and child.

The child depends on aspects of the parent such as:

Output
methods
contracts
accessibility
constructor requirements
overriding rules

Therefore inheritance should be used deliberately.


151. Inheritance and Cohesion#

A parent should have cohesive responsibilities.

For example:

Output
Employee

should contain employee-wide concepts.

It should not become:

Employee
├── database code
├── UI code
├── email code
├── payment gateway code
└── unrelated utility methods

152. Inheritance and SOLID Preview#

Inheritance is strongly related to the SOLID principles.

Especially:

Output
Liskov Substitution Principle

The basic idea is that subtypes should be substitutable for their parent type without violating expected behavior.

Detailed SOLID discussion appears in Chapter 23.


153. Practical Design Test#

Before writing:

Java
class Child extends Parent

ask:

Output
1. Is Child genuinely a Parent?
2. Does Child satisfy the Parent contract?
3. Does Child need the Parent behavior?
4. Is the relationship stable?
5. Would composition be better?
6. Does the hierarchy make the code simpler?

154. Inheritance Decision Example#

Question:

Output
Should Manager extend Employee?

Usually:

Output
Yes, if Manager is modeled as a specialized Employee.

Question:

Output
Should Car extend Engine?

Usually:

Output
No.

Because:

Output
Car HAS-A Engine.

155. Inheritance Decision Example — Student#

Output
Student IS-A Person

This is a common model.

But a real system may choose different modeling depending on domain requirements.

Inheritance should always reflect the intended domain model.


156. Inheritance Decision Example — Address#

Usually:

Output
Student HAS-A Address

not:

Output
Student IS-A Address

So use composition:

Java
class Student {

    private Address address;
}

157. Inheritance Decision Example — Engine#

Usually:

Output
Car HAS-A Engine

Use:

Java
class Car {

    private Engine engine;
}

158. Inheritance Decision Example — Payment#

Suppose:

Payment
├── CardPayment
├── CashPayment
└── UpiPayment

If these genuinely share a common Payment contract and behavior, inheritance or an interface hierarchy may be appropriate.

The exact design depends on the system.


159. Inheritance and Interfaces#

Sometimes the better abstraction is:

Output
interface Payable

rather than:

Output
class Payment

A class can then implement multiple interfaces.

This is why interfaces are an important complement to class inheritance.

Chapter 21 covers interfaces deeply.


160. Java Class Inheritance Summary#

For classes:

Output
one direct superclass

Possible structures:

Output
A → B
Output
A → B → C
Output
    A
   / \
  B   C

Not:

Output
A   B
 \ /
  C

through multiple class inheritance.


161. Constructor Summary#

Remember:

Output
constructors are not inherited

But:

Output
super(...)

allows a subclass constructor to invoke a superclass constructor.

Execution:

parent initialization
      ↓
parent constructor
      ↓
child initialization
      ↓
child constructor

162. super Summary#

Output
super()
→ parent no-argument constructor

super(args)
→ parent constructor with matching args

super.field
→ parent field

super.method()
→ parent instance method implementation

163. Inheritance Summary#

Output
extends
→ class inheritance

parent
→ superclass

child
→ subclass

IS-A
→ subtype relationship

HAS-A
→ usually composition

164. Access Summary#

Output
private
→ directly accessible only inside declaring class

package-private
→ accessible within package

protected
→ package access plus specific subclass access rules

public
→ broadly accessible

Detailed access behavior is covered in Chapter 24.


165. Method Summary#

Output
inherited method
→ child can use accessible parent implementation

overridden method
→ child provides specialized instance implementation

super.method()
→ explicitly use parent implementation

static method
→ hidden, not dynamically overridden

166. Field Summary#

Output
fields are not overridden

If child declares the same field name:

Output
field hiding

Use:

Java
super.field

to explicitly access the parent field when it is accessible.


167. Object Type Summary#

For:

Java
Animal a = new Dog();

remember:

Output
reference type = Animal
object type    = Dog

Direct member access is checked using the reference type.

Overridden instance methods can dispatch according to the runtime object.


168. Interview Questions — Basic#

Q1. What is inheritance?#

Inheritance is an OOP mechanism in which a subclass derives from a superclass and can reuse accessible members and specialize behavior.


Q2. Which keyword is used for inheritance in Java?#

Java
extends

Q3. What is a superclass?#

The class from which another class directly inherits.


Q4. What is a subclass?#

A class that directly extends another class.


Q5. What is an IS-A relationship?#

It describes a subtype relationship.

Example:

Output
Dog IS-A Animal

Q6. What is single inheritance?#

A class has one direct superclass.


Q7. What is multilevel inheritance?#

Inheritance through multiple levels.

Example:

A
↑
B
↑
C

Q8. What is hierarchical inheritance?#

Multiple subclasses share a common superclass.

Example:

Output
    A
   / \
  B   C

Q9. Does Java support multiple inheritance of classes?#

No.

A class can directly extend only one class.


Q10. Why does Java not support multiple class inheritance?#

One reason is to avoid ambiguity associated with multiple superclass implementations, such as the classic diamond problem.


169. Interview Questions — Constructors#

Q11. Are constructors inherited?#

No.


Q12. How does a subclass invoke a superclass constructor?#

Using:

Java
super(...)

Q13. What happens if a child constructor does not explicitly call super()?#

Java attempts to insert an implicit no-argument superclass constructor invocation, provided that constructor is accessible and exists.


Q14. What if the parent has only a parameterized constructor?#

The child must explicitly invoke an accessible matching constructor.

Example:

Java
Child() {
    super("value");
}

Q15. Can super() and this() both appear as the first constructor invocation?#

No.

A constructor can begin with one constructor invocation, either:

Java
this(...)

or:

Java
super(...)

Q16. Why does the superclass constructor execute before the child constructor body?#

Superclass state must be initialized as part of constructing the subclass object.


170. Interview Questions — super#

Q17. What is the use of super?#

It provides access to superclass context.

Common forms:

Output
super()
super(args)
super.field
super.method()

Q18. What is super.method()?#

It explicitly invokes the superclass implementation of an instance method.


Q19. What is super.field?#

It accesses an accessible superclass field when a field with the same name is hidden in the child.


Q20. Can super() be called from a normal method?#

No.

It is a constructor invocation and is used in constructors.


171. Interview Questions — Access#

Q21. Can a child directly access a private parent field?#

No.


Q22. Can a child access a protected parent member?#

Often yes, subject to Java's protected-access rules.


Q23. Why might private fields be preferred over protected fields?#

Private fields preserve stronger encapsulation and reduce subclass dependence on parent representation.


Q24. Can a child use a public parent method?#

Yes, subject to normal access rules.


172. Interview Questions — Methods#

Q25. Are methods inherited?#

Accessible methods can be inherited and used by subclasses according to Java's inheritance rules.


Q26. What is method overriding?#

A subclass provides a specialized implementation of an inherited instance method with a compatible signature.


Q27. What is @Override?#

An annotation that tells the compiler the programmer intends to override an inherited method.


Q28. Are fields overridden?#

No.

Fields can be hidden when a child declares a field with the same name.


Q29. Are static methods overridden?#

No.

A static method can be hidden by a subclass declaration.


Q30. Can a final method be overridden?#

No.


173. Interview Questions — Polymorphism#

Q31. What is upcasting?#

Treating a subclass object as a superclass type.

Example:

Java
Animal a = new Dog();

Q32. Is upcasting safe?#

For a valid subtype relationship, yes.


Q33. What is downcasting?#

Casting a superclass reference back to a more specific subclass type.

Example:

Java
Dog d = (Dog) animal;

Q34. What happens if downcasting is invalid?#

A runtime ClassCastException can occur.


Q35. Why is Animal a = new Dog() useful?#

It allows code to work with a general Animal type while the actual object can be a specialized subtype.


174. Interview Questions — Design#

Q36. What is the difference between inheritance and composition?#

Inheritance represents an IS-A relationship.

Composition represents a HAS-A/contains/uses relationship.


Q37. Why should inheritance not be used only for code reuse?#

Because inheritance creates a strong type and behavioral relationship. Incorrect inheritance can make the design harder to maintain.


Q38. Why is Car extends Engine usually wrong?#

Because a Car is not an Engine.

A Car has an Engine.


Q39. Why can deep inheritance be problematic?#

It increases coupling and makes behavior harder to trace and understand.


Q40. What is the Liskov Substitution Principle?#

It broadly says that objects of a subtype should be usable where the parent type is expected without violating the expected behavior of the parent contract.


175. Output Questions#

Output 1#

Java
class Animal {

    void eat() {
        System.out.println("Eat");
    }
}

class Dog extends Animal {

    void bark() {
        System.out.println("Bark");
    }
}

Dog d = new Dog();

d.eat();
d.bark();

Output:

Output
Eat
Bark

176. Output Question 2#

Java
class A {

    A() {
        System.out.println("A");
    }
}

class B extends A {

    B() {
        System.out.println("B");
    }
}

new B();

Output:

Output
A
B

177. Output Question 3#

Java
class A {

    int x = 10;
}

class B extends A {

    int x = 20;

    void show() {
        System.out.println(x);
        System.out.println(super.x);
    }
}

new B().show();

Output:

Output
20
10

178. Output Question 4#

Java
class Parent {

    void show() {
        System.out.println("Parent");
    }
}

class Child extends Parent {

    @Override
    void show() {
        System.out.println("Child");
        super.show();
    }
}

new Child().show();

Output:

Output
Child
Parent

179. Output Question 5#

Java
class Animal {

    void sound() {
        System.out.println("Animal");
    }
}

class Dog extends Animal {

    @Override
    void sound() {
        System.out.println("Dog");
    }
}

Animal a = new Dog();

a.sound();

Output:

Output
Dog

180. Output Question 6#

Java
class A {

    A() {
        System.out.println("A");
    }
}

class B extends A {

    B() {
        super();
        System.out.println("B");
    }
}

new B();

Output:

Output
A
B

181. Output Question 7#

Java
class A {

    A(String value) {
        System.out.println(value);
    }
}

class B extends A {

    B() {
        super("Hello");
        System.out.println("B");
    }
}

new B();

Output:

Output
Hello
B

182. Output Question 8#

Java
class A {
    void show() {
        System.out.println("A");
    }
}

class B extends A {
    void showB() {
        System.out.println("B");
    }
}

A a = new B();

a.show();

Output:

Output
A

The actual object is B, but B did not override show().


183. Output Question 9#

Java
class A {

    void show() {
        System.out.println("A");
    }
}

class B extends A {

    @Override
    void show() {
        System.out.println("B");
    }
}

A a = new B();

a.show();

Output:

Output
B

Because B overrides the instance method.


184. Output Question 10#

Java
class A {

    int x = 10;
}

class B extends A {

    int x = 20;
}

A a = new B();

System.out.println(a.x);

Output:

Output
10

Fields do not use dynamic method dispatch.

The field access is based on the reference type.


185. Output Question 11#

Java
class A {

    static void show() {
        System.out.println("A");
    }
}

class B extends A {

    static void show() {
        System.out.println("B");
    }
}

A a = new B();

a.show();

Output:

Output
A

Static methods are hidden rather than dynamically overridden.


186. Output Question 12#

Java
class Animal {

    void eat() {
        System.out.println("Eat");
    }
}

class Dog extends Animal {

    void bark() {
        System.out.println("Bark");
    }
}

Animal animal = new Dog();

animal.eat();

Output:

Output
Eat

187. Output Question 13#

Java
class A {

    A() {
        System.out.println("A");
    }
}

class B extends A {

    B() {
        this(10);
    }

    B(int x) {
        System.out.println("B " + x);
    }
}

new B();

Output:

Output
A
B 10

The no-argument B constructor calls another B constructor, which then implicitly calls super().


188. Output Question 14#

Java
class A {

    A() {
        System.out.println("A");
    }
}

class B extends A {

    B() {
        super();
        System.out.println("B");
    }
}

class C extends B {

    C() {
        super();
        System.out.println("C");
    }
}

new C();

Output:

Output
A
B
C

189. Output Question 15#

Java
class Animal {

    void sound() {
        System.out.println("Animal");
    }
}

class Dog extends Animal {

    @Override
    void sound() {
        super.sound();
        System.out.println("Dog");
    }
}

new Dog().sound();

Output:

Output
Animal
Dog

190. Practice Exercise 1#

Create:

Output
Animal
Dog
Cat

Animal should have:

Output
eat()
sleep()

Dog:

Output
bark()

Cat:

Output
meow()

Create objects and call all methods.


191. Practice Exercise 2#

Create:

Output
Vehicle
Car
Bike

Vehicle:

Output
start()
stop()

Car:

Output
drive()

Bike:

Output
ride()

Use constructors to initialize the brand.


192. Practice Exercise 3#

Create:

Output
Person
Student

Person:

Output
name
age

Student:

Output
rollNumber
course

Use:

Java
super(...)

to initialize parent state.


193. Practice Exercise 4#

Create:

Output
Employee
Developer
Manager

Employee:

Output
id
name
work()

Developer:

Output
writeCode()

Manager:

Output
manageTeam()

Use private fields.


194. Practice Exercise 5#

Create:

Output
BankAccount
SavingsAccount

BankAccount:

Output
accountNumber
balance
deposit()
withdraw()

SavingsAccount:

Output
addInterest()

Do not make balance publicly writable.


195. Practice Exercise 6#

Create:

Output
Shape
Circle
Rectangle

Give Shape:

Java
draw()

Override it in Circle and Rectangle.

Then write:

Java
Shape s1 = new Circle();
Shape s2 = new Rectangle();

and call:

Java
s1.draw();
s2.draw();

196. Practice Exercise 7#

Create a three-level hierarchy:

LivingThing
   ↓
Animal
   ↓
Dog

Methods:

Output
LivingThing → breathe()
Animal      → eat()
Dog         → bark()

Create a Dog and call all three.


197. Practice Exercise 8#

Create:

Output
Parent
Child

Both have:

Java
int value

Use:

Java
this.value
super.value

to print both values.


198. Practice Exercise 9#

Create a parent method:

Java
void show()

Override it in the child.

Inside the child:

Java
super.show();

Then add another line.

Observe the output order.


199. Practice Exercise 10#

Create:

Output
Animal
Dog
Cat

Write:

Java
static void makeSound(Animal animal)

Override sound() in Dog and Cat.

Pass both objects to the method.

Observe runtime polymorphism.


200. Mini Project — Employee Management#

Build:

Employee
├── Developer
├── Manager
└── Designer

Employee:

Output
id
name
salary
work()

Developer:

Output
writeCode()

Manager:

Output
manageTeam()

Designer:

Output
designUI()

Use:

Output
constructors
private fields
super()
inheritance
method overriding

201. Mini Project — Vehicle Management#

Build:

Vehicle
├── Car
├── Bike
└── Truck

Vehicle:

Output
brand
speed
start()
stop()

Car:

Output
drive()

Bike:

Output
ride()

Truck:

Output
loadCargo()

Think carefully about what belongs in Vehicle.


202. Mini Project — Banking System#

Build:

BankAccount
├── SavingsAccount
└── CurrentAccount

Common:

Output
account number
balance
deposit

Savings:

Output
interest

Current:

Output
overdraft

Ensure that every subclass respects the parent's rules.


203. Mini Project — School System#

Build:

Person
├── Student
└── Teacher

Person:

Output
name
age

Student:

Output
rollNumber
study()

Teacher:

Output
subject
teach()

Use constructor chaining.


204. Mini Project — Animal System#

Build:

Animal
├── Dog
├── Cat
└── Bird

Common:

Output
name
eat()
sleep()

Dog:

Output
bark()

Cat:

Output
meow()

Bird:

Output
fly()

Then think about whether fly() should belong to Animal or only Bird.

This is a design exercise.


205. Design Challenge#

Suppose you have:

Output
Car
Engine

Question:

Should you write:

Java
class Car extends Engine

or:

Java
class Car {
    private Engine engine;
}

Answer:

Usually composition:

Java
class Car {
    private Engine engine;
}

because:

Output
Car HAS-A Engine

206. Design Challenge#

Suppose:

Output
Developer
Employee

Should Developer extend Employee?

Usually yes if the domain model says:

Output
Developer IS-A Employee

and Developer can satisfy the Employee contract.


207. Design Challenge#

Suppose:

Output
Student
Address

Should Student extend Address?

Usually no.

Use:

Java
class Student {
    private Address address;
}

because:

Output
Student HAS-A Address

208. Design Challenge#

Suppose:

Output
Circle
Shape

Should Circle extend Shape?

Usually yes if Shape is a suitable common abstraction:

Output
Circle IS-A Shape

This can enable polymorphism.


209. Complete Mental Model#

Think of inheritance like this:

Output
             Superclass
                 |
          common behavior
                 |
          +------+------+
          |             |
       Subclass       Subclass
          |             |
     specialization specialization

The parent captures common meaning.

The child adds or specializes meaning.


210. Inheritance in One Example#

Java
class Animal {

    private final String name;

    Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void eat() {
        System.out.println(
            name + " eats"
        );
    }

    public void sound() {
        System.out.println(
            "Generic animal sound"
        );
    }
}

class Dog extends Animal {

    Dog(String name) {
        super(name);
    }

    @Override
    public void sound() {
        System.out.println(
            getName() + " barks"
        );
    }

    public void fetch() {
        System.out.println(
            getName() + " fetches"
        );
    }
}

211. Using the Complete Example#

Java
Animal animal = new Dog("Bruno");

animal.eat();
animal.sound();

Output:

Output
Bruno eats
Bruno barks

The parent reference provides the general type.

The actual Dog object provides the overridden sound behavior.


212. Important Concepts Connected to This Chapter#

Inheritance connects directly to:

Output
Chapter 15
→ Encapsulation

Chapter 17
→ Method Overloading

Chapter 18
→ Method Overriding

Chapter 19
→ Polymorphism

Chapter 20
→ Abstraction

Chapter 21
→ Interfaces

Chapter 22
→ OOP Relationships

Chapter 23
→ OOP Design

This is why inheritance is a central OOP topic.


213. Final Revision#

Remember:

Output
extends
→ class inheritance

Parent
→ superclass

Child
→ subclass

IS-A
→ inheritance relationship

HAS-A
→ composition relationship

super()
→ superclass constructor

super.field
→ superclass field

super.method()
→ superclass method implementation

constructors
→ not inherited

private
→ not directly accessible in subclass

fields
→ not overridden

instance methods
→ can be overridden

static methods
→ hidden, not overridden

final class
→ cannot be extended

final method
→ cannot be overridden

upcasting
→ child object treated as parent type

downcasting
→ parent reference cast to child type

Object
→ root superclass of ordinary Java class hierarchy

214. Most Important Rules#

Output
1. Use extends for class inheritance.

2. A class has only one direct superclass.

3. Java supports single, multilevel, and hierarchical class inheritance.

4. Java does not support multiple inheritance of classes.

5. Constructors are not inherited.

6. Parent constructors execute before child constructor bodies.

7. Use super(...) to invoke a superclass constructor.

8. super(...) must be the constructor's first statement.

9. Use super.method() to explicitly call a superclass instance method.

10. Use super.field for an accessible superclass field.

11. Fields are hidden, not overridden.

12. Instance methods can be overridden.

13. Static methods are hidden rather than dynamically overridden.

14. private parent fields cannot be directly accessed by subclasses.

15. Inheritance should represent a meaningful IS-A relationship.

16. HAS-A relationships usually suggest composition.

17. Upcasting is treating a child object as a parent type.

18. Downcasting should be performed carefully.

19. @Override helps the compiler verify overriding.

20. A final class cannot be extended.

21. A final method cannot be overridden.

22. Inheritance enables many polymorphic designs.

23. Good inheritance is about behavior and contracts, not only code reuse.

24. Prefer encapsulated parent state rather than exposing representation unnecessarily.

25. Keep inheritance hierarchies simple and meaningful.

215. Chapter 16 Complete#

You should now be comfortable with the basic inheritance model:

Diagram
                 Object
                   ↑
                Animal
               /     \
              /       \
            Dog       Cat

You should understand:

class hierarchy
      ↓
extends
      ↓
inheritance
      ↓
IS-A relationship
      ↓
constructor chaining
      ↓
super
      ↓
method inheritance
      ↓
overriding preview
      ↓
polymorphism

The next chapter focuses on a different form of polymorphic behavior:

Chapter 17 — Method Overloading#

You will learn:

  • What method overloading is
  • Why overloading is useful
  • Overloading rules
  • Same method name
  • Different parameter lists
  • Number of parameters
  • Parameter types
  • Parameter order
  • Return type rule
  • Why return type alone cannot overload
  • Primitive widening and overload selection
  • Boxing and unboxing with overloads
  • Varargs and overloads
  • Constructor overloading
  • Compile-time polymorphism
  • Ambiguous overloads
  • null and overloaded methods
  • static method overloading
  • main method overloading
  • Practical programs
  • Exercises
  • Output questions
  • Interview questions
  • Common mistakes