Three classes, one copy-paste bug
Riya is building a small college ERP. She writes Student, then copies it to make Teacher and Staff: each has name, phone and printContact(). Then the principal asks for phone numbers to be printed with +91. She fixes it in Student, forgets Staff, and the notice board shows two formats.
Sir, three classes, the same three members, and I keep fixing bugs in one and forgetting the others.
Ask yourself: is a student a kind of person? Is a teacher? Then write Person once and say class Student extends Person. Student gets name, phone and printContact for free, and adds only roll number.
And the +91 fix?
One place, in Person. Every class that extends it gets the fix. That's inheritance, the second pillar.
What is inheritance?
Inheritance is the mechanism by which one class (the subclass or child) acquires the fields and methods of another class (the superclass or parent), declared in Java with the extends keyword. It models an IS-A relationship, promotes code reuse, and is the basis for method overriding and runtime polymorphism. A Java class can extend exactly one class; every class that extends nothing implicitly extends java.lang.Object.
A child class starts with everything the parent has and then adds its own extras. "A savings account is an account, plus interest."
Words you'll meet in this lesson
Person.Student extends Person.java.lang.Object, the root of every class hierarchy.Inheritance at a glance
| Syntax | class Student extends Person { … } |
|---|---|
| Direct parents | Exactly one class. extends A, B is a compile error. A class can implement many interfaces (Lesson 7.7). |
| Inherited | Public and protected fields and methods; package-private ones too if both classes are in the same package |
| Private members | Present inside the child object, but not accessible by name in the child's code. Reach them through inherited public methods. |
| Constructors | Never inherited. The child writes its own and calls the parent's with super(...) (Lesson 7.3). |
| Root | Every class ends at Object, so every object has toString(), equals(), hashCode() and getClass() |
Exam tip: Java supports single, multilevel and hierarchical inheritance with classes. Multiple and hybrid inheritance are supported only through interfaces. A common MCQ asks "Which inheritance is not supported by classes in Java?": the answer is multiple.
The types of inheritance
Single
One child, one parent.Savings extends Account
Multilevel
A chain: grandchild → child → parent.Manager extends Employee extends Person
Hierarchical
Many children share one parent.Car, Bike, Truck extends Vehicle
Multilevel and hierarchical together
class Vehicle {
String regNo;
void start() { System.out.println(regNo + ": engine on"); }
}
class Car extends Vehicle { // hierarchical: Car and Truck share Vehicle
int seats;
}
class Truck extends Vehicle {
int capacityKg;
}
class ReeferTruck extends Truck { // multilevel: ReeferTruck → Truck → Vehicle
int minTemp;
}
public class Main {
public static void main(String[] args) {
Car c = new Car();
c.regNo = "MH-12-AB-1234";
c.seats = 5;
c.start(); // inherited from Vehicle
ReeferTruck r = new ReeferTruck();
r.regNo = "MH-04-XY-9876"; // from Vehicle (two levels up)
r.capacityKg = 8000; // from Truck
r.minTemp = -18; // its own
r.start();
System.out.println(r.capacityKg + " kg at " + r.minTemp + " C");
}
}| Type | Shape | With classes? | With interfaces? |
|---|---|---|---|
| Single | A ← B | Yes | Yes |
| Multilevel | A ← B ← C | Yes | Yes |
| Hierarchical | A ← B, A ← C | Yes | Yes |
| Multiple | A ← C → B | No (compile error) | Yes: class C implements A, B |
| Hybrid | A mix including multiple | No | Yes, through interfaces |
The diamond problem: if class C extends A, B were allowed and both A and B had hello(), which one should c.hello() run? And if A and B both extend a class with a field, does C get one copy or two? Java avoids this by allowing only one parent class. Interfaces can be combined because they carry no instance fields, and if two interfaces bring the same default method, Java forces the class to choose (Lesson 7.7). Writing class C extends A, B gives error: '{' expected.
Building a small hierarchy
Find what is common, and test IS-A
Employee and Manager both have a name and a salary. Is a manager an employee? Yes. Is a car an engine? No, a car has an engine: use a field, not inheritance.
Inheritance is a permanent, compile-time link. Use it only when the child truly is a special kind of the parent and can be used wherever the parent is expected.Write the parent once
The parent keeps its fields private (Lesson 7.1). Children will reachclass Person { private String name; Person(String name) { this.name = name; } String getName() { return name; } void greet() { System.out.println("Hi, I am " + name); } }nameonly throughgetName()andgreet().Extend it and add only what's new
Constructors are not inherited, so Employee writes its own and first calls Person's withclass Employee extends Person { private double salary; Employee(String name, double salary) { super(name); // hand the name to Person's constructor this.salary = salary; } }super(name). Lesson 7.3 covers this in detail.One object holds every level's fields
There is one object on the heap, not a Person object plus an Employee object. It has room forEmployee e = new Employee("Asha", 50000); e.greet(); // Hi, I am Ashaname(declared in Person) andsalary(declared in Employee). Whene.greet()is called, the JVM looks forgreetin Employee, doesn't find it, and uses Person's.Everything ends at Object
Person extends nothing, so javac makes it extendSystem.out.println(e instanceof Object); // true System.out.println(e.getClass().getSuperclass()); // class PersonObject. That's why every object, even one from your own class, hastoString(),equals()andgetClass()(Lesson 10.3).
One object, many levels: both views
Left: the line being run and its result. Right: the class chain (left column) and the single object on the heap with a section for each level.
- Parent alone: a
Personobject has a name and agreet()method. - Single inheritance:
Employee extends Person. Callinge.greet()works although Employee's code never declares it. - Multilevel:
Manager extends Employee. One Manager object answers methods from all three classes. - Private isn't accessible:
nameis private in Person, so even through a Manager, outside code can't read it directly. - No multiple inheritance: listing two classes after
extendsdoesn't even parse. - Object at the root: a Manager is an Employee, a Person and an Object, all at once.
new Person("Ravi")creates one object with room for Person's fieldname.new Employee(...)creates one object with Person'snameand Employee'ssalary. Forgreet(), the JVM searches Employee first, then its parent.- A Manager object has three sections, one per class in the chain. There is no separate Person object or Employee object.
namephysically lives in the Manager object, butprivatemeans only code written inside Person can use the namename.- With two parents, a call to
greet()and inherited fields would be ambiguous: the diamond problem. Java allows one parent class. Objectsits at the top of every chain. It contributes methods liketoString(), not fields you can see.
Inheritance in real systems
Inheritance is common in libraries and frameworks. In business code, teams use it carefully and prefer composition when the IS-A test is doubtful.
Watch it with an example: finding a method up the hierarchy
SavingsAccount extends Account. When you call a method on a savings account, the JVM looks in SavingsAccount first, then moves up to Account, then Object.
- The call:
sarefers to a SavingsAccount object. Which class's code runs foraddInterest()? - Child first: the JVM looks in the object's own class, SavingsAccount, and finds it there.
- deposit(500): SavingsAccount doesn't define it…
- …so the search moves up to the parent, Account, where it is found. The child reuses the parent's code without copying it.
- toString(): neither SavingsAccount nor Account defines it…
- …so it is found in Object, the root of every class. Bank account types, exception classes and framework base classes all rely on this lookup. (The JVM caches the result, so it is fast.)
1. Java's own exception hierarchy
IOException extends Exception, which extends Throwable. Because of this chain, one catch (Exception e) can handle many specific errors (Module 9).
2. Account types in banking
Savings and current accounts share an account number, holder and deposit logic in a parent class; each child adds its own rules (interest, overdraft limit).
3. Common fields for stored records
Many projects put fields every database record needs (id, created time, updated time) in one base class that all entity classes extend.
4. Framework base classes
UI and testing frameworks often give you a base class to extend. Your class inherits the framework's lifecycle code and fills in only the parts specific to your screen or test.
Examples are simplified. Deep hierarchies (five or more levels) become hard to change; many teams follow "favour composition over inheritance" and keep chains short.
Three levels, one object
class Person {
private String name;
Person(String name) { this.name = name; }
String getName() { return name; }
void greet() { System.out.println("Hi, I am " + name); }
}
class Employee extends Person {
private double salary;
Employee(String name, double salary) {
super(name);
this.salary = salary;
}
double getSalary() { return salary; }
}
class Manager extends Employee {
private int teamSize;
Manager(String name, double salary, int teamSize) {
super(name, salary);
this.teamSize = teamSize;
}
int getTeamSize() { return teamSize; }
}
public class Main {
public static void main(String[] args) {
Manager m = new Manager("Kiran", 90000, 5);
m.greet(); // from Person
System.out.println("Salary: " + m.getSalary()); // from Employee
System.out.println("Team: " + m.getTeamSize()); // its own
System.out.println(m instanceof Employee);
System.out.println(m instanceof Person);
System.out.println(m.getClass().getSuperclass().getSuperclass().getSimpleName());
}
}class Manager extends EmployeeManager inherits from Employee, which inherits from Person: multilevel.super(name, salary);Constructors aren't inherited; this line runs Employee's constructor first (Lesson 7.3).m.greet()Found in Person after the JVM searches Manager and Employee.instanceofTrue for the object's own class and every class above it.
A Bike that uses Vehicle's method
Watch one object (#1) hold a field declared in Vehicle and a field declared in Bike, and see describe() run from the parent class.
Worked examples: real problems, solved and traced in memory
Three hierarchies from real businesses. Run each solution, then step through it: notice that new creates one object whose fields come from every class in the chain, and that an inherited method runs with this pointing at the child object.
Interest on an inherited balance
Problem statement
A bank's Account class already handles deposits and keeps the balance private. Add a SavingsAccount that can credit monthly interest, without copying any of Account's code.
deposit Rs 12000, monthly rate 0.5%
Balance: 12060.0
Approach
- Write
SavingsAccount extends Accountand add only aratefield andcreditInterest(). - The child can't touch the private
balance, so it uses the inheritedgetBalance()anddeposit(). - Create one SavingsAccount and call both inherited and own methods on it.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
A three-level truck, built in one go
Problem statement
A cold-chain company tracks refrigerated trucks. Every vehicle has a registration number; every truck has a capacity; a refrigerated truck also has a minimum temperature. Create one refrigerated truck and print a dispatch line.
ReeferTruck "MH-04-XY-9876", 8000 kg, -18 C
MH-04-XY-9876 | 8000 kg | -18 C
Approach
- Build a chain:
Vehicle → Truck → ReeferTruck, each with its own field and constructor. - Each constructor first calls its parent's constructor with
super(...), passing the values up. - Watch three constructor frames stack up, then unwind, while one object (#1) fills in.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
One parent method, two different children
Problem statement
An office prints ID badges. Developers and testers are both employees with a name; each adds one detail of their own. The badge-printing code must be written only once.
Developer "Neha" (team Payments), Tester "Imran" (team Search)
Neha [Payments] Java Imran [Search] Selenium
Approach
- Put
name,teamandbadge()in the parentEmployee. DeveloperandTesterextend it: hierarchical inheritance.- Call the same inherited
badge()on both objects and watchthischange.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Check yourself
Quick revision
Lesson 7.2 in one screen
- Inheritance: a subclass gets the superclass's members with
extends; it models IS-A. - Types with classes: single, multilevel, hierarchical. Multiple and hybrid: only via interfaces.
- One parent class only:
extends A, Bdoesn't compile (diamond problem). - Private members exist in the child object but aren't accessible by name; use the parent's methods.
- Constructors are not inherited; the child calls the parent's with
super(...). new Child()creates one object holding every level's fields.- Every class ultimately extends
Object.
Interview and viva questions
Why doesn't Java support multiple inheritance of classes?
To avoid the diamond problem and keep the language simple. If a class had two parents with the same method, a call would be ambiguous; if both inherited fields from a common ancestor, the object's layout would be unclear. Java allows multiple inheritance of type through interfaces, which have no instance fields, and resolves clashing default methods by forcing the class to override.
Is a private member inherited?
The private field is present in the child object (memory is set aside for it), but it is not inherited as an accessible member: the child's code can't name it. The child uses it indirectly through the parent's public or protected methods. Interviewers accept either wording if you explain this difference.
What is the difference between IS-A and HAS-A?
IS-A is inheritance: a SavingsAccount is an Account. HAS-A is composition: a Car has an Engine field. Composition is more flexible because the part can be replaced at run time and the classes stay loosely coupled.
Why are constructors not inherited?
A constructor's job is to initialise an object of its own class. A parent's constructor knows nothing about the child's extra fields, so letting new Child(...) use it would leave the child part uninitialised. Instead every child constructor calls a parent constructor first (explicitly or implicitly) and then sets up its own part.
When should you avoid inheritance?
When the IS-A test fails, when you only want to reuse a few methods, or when the parent may change often. Prefer composition then. A well-known example is Java's own java.util.Stack, which extends Vector: every stack also inherits methods like add(int index, E element) that break the last-in, first-out rule.
Practice problems
For each problem, first draw the class hierarchy on paper (parent at the top, arrows pointing up), then decide which class each field and method belongs in. The last three are business problems.
Dog inherits from Animal
Create Animal with a name field and an eat() method. Create Dog extends Animal with its own bark(). Call both methods on a Dog.
Dog named "Sheru"
Sheru is eating Sheru says Woof
Show solution and explanation
class Animal {
String name;
void eat() {
System.out.println(name + " is eating");
}
}
class Dog extends Animal {
void bark() {
System.out.println(name + " says Woof");
}
}
public class Main {
public static void main(String[] args) {
Dog d = new Dog();
d.name = "Sheru";
d.eat();
d.bark();
}
}How it works: Dog declares only bark(), yet d.eat() and d.name work because they are inherited from Animal. Inside bark(), the inherited field name is used just like Dog's own.
Which class is the parent?
Use getClass().getSuperclass() to print the parent of Student, then the parent of Person, for the hierarchy Student extends Person.
class Person {} class Student extends Person {}Class: Student Parent: Person Grandparent: Object
Show solution and explanation
class Person { }
class Student extends Person { }
public class Main {
public static void main(String[] args) {
Student s = new Student();
System.out.println("Class: " + s.getClass().getSimpleName());
System.out.println("Parent: " + s.getClass().getSuperclass().getSimpleName());
System.out.println("Grandparent: " + s.getClass().getSuperclass().getSuperclass().getSimpleName());
}
}How it works: Person has no extends, so javac makes it extend Object. That's why the grandparent of Student is Object. getClass() itself is a method every object inherits from Object.
Rectangle and Square (multilevel)
Make Shape with a colour, Rectangle extends Shape with length and width and an area() method, and Square extends Rectangle with a method setSide(int) that sets both sides. Print a red square's area.
Square, colour red, side 6
A red square of area 36
Show solution and explanation
class Shape {
String colour;
}
class Rectangle extends Shape {
int length, width;
int area() {
return length * width;
}
}
class Square extends Rectangle {
void setSide(int side) {
length = side;
width = side;
}
}
public class Main {
public static void main(String[] args) {
Square sq = new Square();
sq.colour = "red";
sq.setSide(6);
System.out.println("A " + sq.colour + " square of area " + sq.area());
}
}How it works: a three-level chain. colour comes from Shape (two levels up), length, width and area() from Rectangle, setSide is Square's own. One Square object holds all three fields.
instanceof up the chain
For Laptop extends Computer extends Device, check whether a Laptop object is an instance of each class and of Object. Also check whether a plain Device is a Laptop.
new Laptop(), new Device()
laptop is Computer: true laptop is Device: true laptop is Object: true device is Laptop: false
Show solution and explanation
class Device { }
class Computer extends Device { }
class Laptop extends Computer { }
public class Main {
public static void main(String[] args) {
Laptop l = new Laptop();
Device d = new Device();
System.out.println("laptop is Computer: " + (l instanceof Computer));
System.out.println("laptop is Device: " + (l instanceof Device));
System.out.println("laptop is Object: " + (l instanceof Object));
System.out.println("device is Laptop: " + (d instanceof Laptop));
}
}How it works: IS-A works only upward. Every Laptop is a Computer, a Device and an Object. A plain Device is not a Laptop, because a Device object doesn't have the Laptop part.
Hierarchical: three kinds of employees
Employee has a name and a describe() method. Developer, Tester and Designer each extend Employee and add one field of their own (language, tool, software). Create one of each and print their details.
Dev "Neha" (Java), Tester "Imran" (Selenium), Designer "Pooja" (Figma)
Neha - codes in Java Imran - tests with Selenium Pooja - designs in Figma
Show solution and explanation
class Employee {
String name;
void describe() {
System.out.print(name + " - ");
}
}
class Developer extends Employee {
String language;
}
class Tester extends Employee {
String tool;
}
class Designer extends Employee {
String software;
}
public class Main {
public static void main(String[] args) {
Developer d = new Developer();
d.name = "Neha";
d.language = "Java";
Tester t = new Tester();
t.name = "Imran";
t.tool = "Selenium";
Designer g = new Designer();
g.name = "Pooja";
g.software = "Figma";
d.describe(); System.out.println("codes in " + d.language);
t.describe(); System.out.println("tests with " + t.tool);
g.describe(); System.out.println("designs in " + g.software);
}
}How it works: three children share one parent: hierarchical inheritance. The common part (name, describe) is written once. Each child adds only its special field. A Tester has no language field: siblings don't share each other's members.
Private field, public door
Account has a private balance and a public deposit() and getBalance(). SavingsAccount extends Account adds addInterest(rate). Since the child can't touch balance directly, implement addInterest using the inherited methods.
deposit 20000, interest 3.5%
Balance after interest: 20700.0
Show solution and explanation
class Account {
private double balance;
public void deposit(double amount) {
if (amount > 0) balance += amount;
}
public double getBalance() {
return balance;
}
}
class SavingsAccount extends Account {
void addInterest(double ratePercent) {
double interest = getBalance() * ratePercent / 100;
deposit(interest);
}
}
public class Main {
public static void main(String[] args) {
SavingsAccount s = new SavingsAccount();
s.deposit(20000);
s.addInterest(3.5);
System.out.println("Balance after interest: " + s.getBalance());
}
}How it works: writing balance += interest in SavingsAccount would be a compile error: balance has private access in Account. Using getBalance() and deposit() keeps the parent's rules in force for the child too: encapsulation and inheritance working together.
Count objects at every level
Each class in Vehicle → Car → SportsCar keeps a static counter that its constructor increases. Create 2 Vehicles, 1 Car and 2 SportsCars and print all three counters. Predict first.
2 Vehicle, 1 Car, 2 SportsCar
Vehicle constructor ran 5 times Car constructor ran 3 times SportsCar constructor ran 2 times
Show solution and explanation
class Vehicle {
static int count;
Vehicle() { count++; }
}
class Car extends Vehicle {
static int count;
Car() { count++; }
}
class SportsCar extends Car {
static int count;
SportsCar() { count++; }
}
public class Main {
public static void main(String[] args) {
new Vehicle(); new Vehicle();
new Car();
new SportsCar(); new SportsCar();
System.out.println("Vehicle constructor ran " + Vehicle.count + " times");
System.out.println("Car constructor ran " + Car.count + " times");
System.out.println("SportsCar constructor ran " + SportsCar.count + " times");
}
}How it works: creating a SportsCar runs SportsCar's constructor, which first (silently) runs Car's, which first runs Vehicle's. So every SportsCar also counts as a Car and a Vehicle: Vehicle 2 + 1 + 2 = 5, Car 1 + 2 = 3, SportsCar 2. Lesson 7.3 explains this hidden super() call.
Savings and current accounts
A bank has savings accounts (4% yearly interest) and current accounts (overdraft up to Rs 10,000). Both share account number, balance and deposit. Write the classes and show a savings account earning one year's interest and a current account going into overdraft.
Savings SB-01 deposit 50000, add yearly interest Current CA-07 deposit 5000, withdraw 12000
SB-01: Rs 52000.0 Withdraw 12000: true CA-07: Rs -7000.0
Show solution and explanation
class Account {
private final String accountNo;
protected double balance;
Account(String accountNo) {
this.accountNo = accountNo;
}
void deposit(double amount) {
if (amount > 0) balance += amount;
}
String summary() {
return accountNo + ": Rs " + balance;
}
}
class SavingsAccount extends Account {
SavingsAccount(String no) { super(no); }
void addYearlyInterest() {
balance += balance * 0.04;
}
}
class CurrentAccount extends Account {
private static final double OVERDRAFT = 10000;
CurrentAccount(String no) { super(no); }
boolean withdraw(double amount) {
if (balance - amount < -OVERDRAFT) return false;
balance -= amount;
return true;
}
}
public class Main {
public static void main(String[] args) {
SavingsAccount s = new SavingsAccount("SB-01");
s.deposit(50000);
s.addYearlyInterest();
System.out.println(s.summary());
CurrentAccount c = new CurrentAccount("CA-07");
c.deposit(5000);
System.out.println("Withdraw 12000: " + c.withdraw(12000));
System.out.println(c.summary());
}
}How it works:
- Common data and
deposit/summarylive inAccount; each child adds only its own rule. balanceisprotectedhere so children can update it directly;accountNostays private and read-only.- 5000 − 12000 = −7000, which is within the Rs 10,000 overdraft, so the withdrawal is allowed.
Payroll for full-time and contract staff
Full-time staff get basic + 40% HRA; contract staff get an hourly rate × hours. Both have an employee ID and name and a method to print a payslip line. Design the hierarchy and print payslips for one of each.
FullTime E101 "Anil", basic 40000 Contract C207 "Sara", Rs 600/hour × 120 hours
E101 Anil Rs 56,000.00 C207 Sara Rs 72,000.00
Show solution and explanation
class Employee {
private final String id;
private final String name;
Employee(String id, String name) {
this.id = id;
this.name = name;
}
void printSlip(double pay) {
System.out.printf("%s %-6s Rs %,.2f%n", id, name, pay);
}
}
class FullTimeEmployee extends Employee {
private final double basic;
FullTimeEmployee(String id, String name, double basic) {
super(id, name);
this.basic = basic;
}
double monthlyPay() {
return basic + basic * 0.40;
}
}
class ContractEmployee extends Employee {
private final double hourlyRate;
private final int hours;
ContractEmployee(String id, String name, double hourlyRate, int hours) {
super(id, name);
this.hourlyRate = hourlyRate;
this.hours = hours;
}
double monthlyPay() {
return hourlyRate * hours;
}
}
public class Main {
public static void main(String[] args) {
FullTimeEmployee f = new FullTimeEmployee("E101", "Anil", 40000);
ContractEmployee c = new ContractEmployee("C207", "Sara", 600, 120);
f.printSlip(f.monthlyPay());
c.printSlip(c.monthlyPay());
}
}How it works:
- ID, name and payslip formatting are common, so they live in
Employee. The pay rules differ, so each child has its ownmonthlyPay(). %,.2fprints Indian-readable amounts with commas and two decimals;%-6spads the name.- Notice both children have a method with the same name. In Lesson 7.4 you'll declare it in the parent and override it, so a payroll loop can treat all employees alike.
Delivery vehicles: can it carry the parcel?
A courier company has bikes (max 20 kg) and vans (max 800 kg, needs a driver with a commercial licence). All vehicles have a registration number and a canCarry(weight) check based on their limit. Check a 15 kg and a 120 kg parcel for one bike and one van.
Bike MH-02-1111 (20 kg), Van MH-02-9999 (800 kg) parcels 15 kg and 120 kg
15 kg -> bike true, van true 120 kg -> bike false, van true MH-02-9999 needs commercial licence: true
Show solution and explanation
class DeliveryVehicle {
private final String regNo;
private final int maxKg;
DeliveryVehicle(String regNo, int maxKg) {
this.regNo = regNo;
this.maxKg = maxKg;
}
boolean canCarry(int kg) {
return kg <= maxKg;
}
String getRegNo() { return regNo; }
}
class Bike extends DeliveryVehicle {
Bike(String regNo) { super(regNo, 20); }
}
class Van extends DeliveryVehicle {
private final boolean commercialLicence = true;
Van(String regNo) { super(regNo, 800); }
boolean needsCommercialLicence() { return commercialLicence; }
}
public class Main {
public static void main(String[] args) {
Bike b = new Bike("MH-02-1111");
Van v = new Van("MH-02-9999");
int[] parcels = {15, 120};
for (int kg : parcels) {
System.out.println(kg + " kg -> bike " + b.canCarry(kg) + ", van " + v.canCarry(kg));
}
System.out.println(v.getRegNo() + " needs commercial licence: " + v.needsCommercialLicence());
}
}How it works:
- The rule
kg <= maxKgis the same for every vehicle, so it's written once in the parent. Children only supply their limit throughsuper(regNo, 20). - Van adds a behaviour the bike doesn't have. Hierarchical inheritance: two children, one parent.
- Adding a new vehicle type (a three-wheeler, 300 kg) is one small class.
Real-world scenario questions (asked in company interviews)
Inheritance saves code when the IS-A test holds and causes pain when it doesn't. Decide your answer first, then open the model answer.
Designing savings and current accounts
A bank needs savings accounts (interest, minimum balance) and current accounts (overdraft limit, no interest). Both have account number, holder name, balance and deposit. How would you design the classes?
The interviewer is checking: can you find the common parent and keep each child's rules separate?
Show a strong answer
- A parent
Accountwith privateaccountNo,holder,balance, plusdeposit()andgetBalance(). SavingsAccount extends AccountaddsrateandaddInterest();CurrentAccount extends AccountaddsoverdraftLimit.- Each child has its own withdraw rule (minimum balance vs overdraft), which is where overriding comes in (Lesson 7.4).
- Both pass the IS-A test, and code that needs "any account" can accept
Account.
Avoid: one class with a type field and if-else everywhere. Every new account type would change every method.
"ElectricTruck extends Truck, Battery"
A delivery company adds electric trucks. A developer wants ElectricTruck to extend both Truck and Battery to reuse chargeLevel(), and is surprised it doesn't compile. What do you suggest?
The interviewer is checking: do you know the single-parent rule and when to use composition?
Show a strong answer
- Java allows one parent class. More importantly, a truck is not a battery; it has a battery.
- Design:
ElectricTruck extends Truckwith a fieldprivate final Battery battery, and a methodchargeLevel()that delegates tobattery.level(). - If many vehicle types need to be "chargeable", define an interface
Chargeableand implement it (Lesson 7.7).
Avoid: making Battery the parent of Truck just to get the method. The hierarchy would make no sense.
The six-level product hierarchy
A catalogue has Product → Electronics → Mobile → Smartphone → AndroidPhone → FoldablePhone. Adding a "refurbished" option now needs a parallel set of classes for every level. What went wrong and how would you restructure?
The interviewer is checking: do you recognise when inheritance is being used for data that should be attributes?
Show a strong answer
- The hierarchy encodes data (category, OS, form factor, condition) as classes. Every new dimension multiplies the number of classes.
- Keep a shallow hierarchy only where behaviour truly differs, and model the rest as fields:
category,attributesmap,conditionenum (Lesson 10.4). - Shared behaviour like pricing rules can be separate objects composed into the product.
Avoid: adding RefurbishedFoldablePhone and friends. Deep, wide hierarchies are hard to change.
A parent-class change broke ten teams
Your platform team owns BaseService, which 40 services across ten teams extend. You add a validation step inside one of its methods, and several child services break because they depended on the old internal order of calls. How do you prevent this in future?
The interviewer is checking: do you understand that inheritance tightly couples children to the parent's internals?
Show a strong answer
- This is the "fragile base class" problem: children depend on how the parent works, not just what it promises.
- Prefer composition for shared libraries: services use helper objects instead of extending a base class.
- Where inheritance stays, document which methods are meant to be overridden, make the rest
final(Lesson 7.8), and use template methods with clear hooks (Lesson 7.6). - Version the library and run the dependent teams' tests before releasing.
Avoid: blaming the child teams. A widely extended base class is a public contract.