Inheritance in Java
Inheritance lets a subclass acquire the members of a superclass, creating an is-a relationship that polymorphism is built on.
-
Java Basics
- Introduction to Java
- Setting Up Java and Writing Your First Program
- Variables, Data Types and Literals in Java
- Type Casting and Type Conversion in Java
- Operators and Expressions in Java
- Input and Output in Java
- Comments, Keywords and Naming Conventions in Java
- Control Flow in Java: if, else and switch
- Loops in Java: for, while and do-while
- Methods
- Arrays and Strings
-
OOP
- Classes and Objects in Java
- Constructors in Java
- The this Keyword in Java
- The static Keyword in Java
- Encapsulation in Java
- Access Modifiers in Java
- Inheritance in Java
- Method Overriding and super in Java
- Polymorphism in Java
- Abstraction, Abstract Classes and Interfaces in Java
- Composition, Aggregation and Association in Java
- The Object Lifecycle in Java
- Core Java
- Exception Handling
-
Collections
- The Java Collections Framework
- List in Java: ArrayList, LinkedList, Vector and Stack
- Set in Java: HashSet, LinkedHashSet and TreeSet
- Map in Java: HashMap, LinkedHashMap and TreeMap
- How HashMap Works Internally in Java
- Queue and Deque in Java: ArrayDeque and PriorityQueue
- Iterators in Java
- Comparable and Comparator in Java
- Collections Utilities and Choosing the Right Collection
- Generics
- Java 8+
- Stream API
- Date and Time
- File and I/O
-
Multithreading
- Threads in Java: Processes, Runnable and Thread
- Thread Lifecycle in Java
- Synchronization in Java: synchronized and volatile
- Locks and Atomic Classes in Java
- Race Conditions and Deadlocks in Java
- The Executor Framework and Thread Pools in Java
- Future and CompletableFuture in Java
- Concurrent Collections in Java
- The Java Memory Model
- JVM and Memory
- Advanced Java
- Networking
- JDBC
- Testing
Definition
Inheritance allows one class, the subclass, to acquire the accessible fields and methods of another, the superclass. The subclass may add members of its own and may replace inherited behaviour.
class Subclass extends Superclass { }Why it exists
- Behaviour shared by several types is written once.
- It establishes an is-a relationship the compiler can check.
- It makes runtime polymorphism possible, which is the real payoff.
Example
class Vehicle {
private final String registration;
Vehicle(String registration) {
this.registration = registration;
}
String registration() {
return registration;
}
String describe() {
return "Vehicle " + registration;
}
}
class Taxi extends Vehicle {
private final int seats;
Taxi(String registration, int seats) {
super(registration); // the superclass part is built first
this.seats = seats;
}
@Override
String describe() {
return "Taxi " + registration() + " with " + seats + " seats";
}
}Vehicle v = new Taxi("TN-09-4471", 4);
System.out.println(v.describe()); // Taxi TN-09-4471 with 4 seatsThe variable is declared as Vehicle, but the object is a Taxi, so the override runs. That is polymorphism, and inheritance is what enables it.
What is and is not inherited
| Member | Inherited |
|---|---|
public and protected members | Yes |
| Package private members | Only within the same package |
private members | No, though they still exist in the object |
| Constructors | No |
| Static members | Accessible, but hidden rather than overridden |
A private field is not inherited, but it is still part of the object in memory. The subclass simply cannot name it, and must go through an accessible method instead.
Types of inheritance in Java
| Type | Supported | Note |
|---|---|---|
| Single | Yes | One subclass extends one superclass. |
| Multilevel | Yes | A subclass is itself extended. |
| Hierarchical | Yes | Several subclasses share one superclass. |
| Multiple, using classes | No | A class extends exactly one class. |
| Multiple, using interfaces | Yes | A class may implement many interfaces. |
Why multiple class inheritance was left out
If two superclasses both provided a save() method, the compiler could not decide which one an instance inherits. That ambiguity is often called the diamond problem. Interfaces avoid it because, historically, they carried no implementation. Since Java 8 interfaces may have default methods, so the language added an explicit rule: when two interfaces supply the same default method, the implementing class must override it and may choose one with InterfaceName.super.method().
interface Printable { default String format() { return "printable"; } }
interface Exportable { default String format() { return "exportable"; } }
class Report implements Printable, Exportable {
@Override
public String format() {
return Printable.super.format(); // the ambiguity must be resolved
}
}Constructors and the chain
A subclass constructor always runs a superclass constructor first, whether or not super(...) is written. If the superclass has no no argument constructor and the subclass does not call one explicitly, the code does not compile.
new Taxi(...)
-> Object()
-> Vehicle(registration)
-> Taxi(registration, seats)Every class inherits from Object
A class with no extends clause implicitly extends Object. That is where toString, equals, hashCode and getClass come from, and why they are available on every reference.
Preventing inheritance
public final class TaxCalculator { } // cannot be extended
public class Base {
public final void audit() { } // cannot be overridden
}Since Java 17, sealed offers a middle position: the superclass names exactly which classes may extend it.
public sealed class Payment permits CardPayment, UpiPayment { }Common mistakes
- Using inheritance for code reuse when there is no is-a relationship. A
Stackis not aVector, and treating it as one exposes operations that break it. - Building deep hierarchies. Beyond two or three levels, behaviour becomes hard to trace.
- Making fields
protected, which locks the representation for every future subclass. - Calling an overridable method from a constructor, so the override runs before the subclass fields exist.
- Expecting a private method to be overridden. It is not inherited, so a subclass method of the same name is unrelated.
Best practices
- Ask whether the subtype can be substituted anywhere the supertype is expected. If not, the relationship is wrong.
- Prefer composition unless inheritance is clearly the better model.
- Design for inheritance deliberately, or make the class
final. - Document what a subclass may override and what it must not.
- Keep superclass fields private and expose protected accessors only when needed.
Practice
- Model
Employee,ManagerandInternand decide which methods belong where. - Why does
class Child extends Parent { Child() { } }fail whenParentonly hasParent(String)? - Two interfaces provide the same default method. Write the class that resolves it.
- Explain why a
Square extends Rectanglewith asetWidthmethod is a design problem. - Convert a two level hierarchy into composition and compare the two designs.
Conclusion
Inheritance expresses is-a and unlocks polymorphism. Use it when the subtype can honestly stand in for the supertype, keep hierarchies shallow, and prefer composition whenever the relationship is really has-a.