What is Inheritance? Inheritance is a mechanism in Java where one class (subclass or child) can inherit the fields and methods of another class (superclass or parent).
This promotes code reuse, hierarchical classification, and polymorphism.
Overview:
Term | Meaning |
---|---|
Superclass (Base Class) | The class whose properties are inherited (Parent ) |
Subclass (Derived Class) | The class that inherits the superclass (Child ) |
extends keyword |
Used to declare that one class inherits another |
| Concept | Description | | ———— | —————————————— | | Inheritance | One class inherits another | | Superclass | Provides common functionality | | Subclass | Specializes or extends superclass behavior | | extends | Keyword for inheritance | | Constructors | Not inherited | | Access | Controlled via access modifiers |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Superclass
class Animal {
void makeSound() {
System.out.println("Animal makes sound");
}
}
// Subclass
class Dog extends Animal {
void bark() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Dog d = new Dog();
d.makeSound(); // Inherited from Animal
d.bark(); // Specific to Dog
}
}
Dog inherits makeSound() from Animal. It also defines its own method bark().
Java supports multilevel (not multiple) inheritance:
1
2
3
4
5
6
7
8
9
10
11
class Animal {
void eat() { System.out.println("eating..."); }
}
class Dog extends Animal {
void bark() { System.out.println("barking..."); }
}
class Puppy extends Dog {
void weep() { System.out.println("weeping..."); }
}
Java does not support multiple inheritance for classes to avoid ambiguity (known as the diamond problem).
However, OOP has multiple inheritance properties.
1
2
3
class A {}
class B {}
// class C extends A, B {} // => Compilation Error
Java handles this via interfaces.
Modifier | Inherited in Subclass? | Accessible in Subclass? |
---|---|---|
public |
Yes | Yes |
protected |
Yes | Yes (even from another package) |
default | Yes (same package only) | Yes (same package only) |
private |
No | No |
1
2
3
4
5
6
7
8
9
10
11
12
class Animal {
Animal() {
System.out.println("Animal constructor");
}
}
class Dog extends Animal {
Dog() {
super(); // optional if superclass has no-arg constructor
System.out.println("Dog constructor");
}
}
Inheritance is used to model “is-a” relationships in object-oriented design. This section covers how classes relate to each other in Java using inheritance, including practical examples and guidelines.
Topic | Summary |
---|---|
is-a relationship | Subclass inherits behavior from superclass |
Common hierarchies | Employee–Manager, Animal–Dog, etc. |
Use cases | Reusability, extensibility |
Composition vs Inheritance | Use composition for “has-a”, inheritance for “is-a” |
B
extends class A
, then B is-a A
.Example:
1
2
3
4
5
class Animal { }
class Dog extends Animal { }
Dog d = new Dog();
System.out.println(d instanceof Animal); // true
A Dog is an Animal
Superclass | Subclasses |
---|---|
Animal |
Dog , Cat , Bird |
Shape |
Circle , Rectangle , Triangle |
Employee |
Manager , Developer , Intern |
Vehicle |
Car , Truck , Bicycle |
Account |
SavingAccount , CheckingAccount |
Each subclass inherits shared behavior and adds specific behavior.
a) Generalization to Specialization
Start with a general concept and refine it.
1
2
3
4
5
6
7
class Vehicle {
void move() { System.out.println("Moving..."); }
}
class Car extends Vehicle {
void playMusic() { System.out.println("Playing music..."); }
}
b) Common Interface Extraction
When multiple classes share behavior, extract a superclass or interface:
1
2
3
4
5
6
7
8
9
10
11
12
class Dog {
void bark() { }
}
class Cat {
void meow() { }
}
// Both can be made subclasses of Animal
class Animal {
void makeSound() { }
}
Relationship Meaning Implementation is-a One class is a type of another Use extends / implements has-a One class contains another Use object composition
Example:
1
2
3
4
5
class Engine { }
class Car {
private Engine engine; // has-a relationship
}
Use inheritance when:
Avoid inheritance if:
1
2
3
Animal
/ \
Dog Cat
When using inheritance, functions (methods) play a central role in how behavior is shared and customized across a class hierarchy. Java allows you to inherit, override, and extend methods in subclasses.
If a superclass has a method, the subclass automatically inherits it — unless it overrides the method.
1
2
3
4
5
6
7
8
9
class Animal {
void makeSound() {
System.out.println("Some animal sound");
}
}
class Dog extends Animal {
// Inherits makeSound() by default
}
1
2
Dog d = new Dog();
d.makeSound(); // prints "Some animal sound"
A subclass can override a method to provide its own version of the behavior.
1
2
3
4
5
6
7
8
9
10
11
12
class Animal {
void makeSound() {
System.out.println("Some animal sound");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark!");
}
}
1
2
Animal a = new Dog();
a.makeSound(); // prints "Bark!" – Dog's version
Overriding enables runtime polymorphism
You can call the original version of the method from the superclass using super.
1
2
3
4
5
6
7
8
9
10
11
12
13
class Animal {
void makeSound() {
System.out.println("Generic animal sound");
}
}
class Dog extends Animal {
@Override
void makeSound() {
super.makeSound(); // Call parent version
System.out.println("...and also Bark!");
}
}
Modifier | Inherited? | Overridable? | Accessible in Subclass? |
---|---|---|---|
public |
✅ | ✅ | ✅ |
protected |
✅ | ✅ | ✅ |
default | ✅ (same package) | ✅ | ✅ (same package) |
private |
❌ | ❌ | ❌ |
An abstract method is a method declared without an implementation in an abstract class. Subclasses must implement it.
1
2
3
4
5
6
7
8
9
10
abstract class Animal {
abstract void makeSound();
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("Meow");
}
}
Concept | Overloading | Overriding |
---|---|---|
Definition | Same method name, different parameters | Redefining inherited method |
Class | Same class | Parent–child relationship |
Return Type | Can vary | Must be same (or subtype) |
Static | Applies to static methods | Not allowed for static methods |
instanceof
OperatorThe instanceof operator is used to test whether an object is an instance of a specific class, subclass, or interface.
It returns a boolean value:
Syntax:
1
object instanceof ClassName
Example:
1
2
3
4
5
6
7
8
9
10
11
12
class Animal {}
class Dog extends Animal {}
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
System.out.println(a instanceof Dog); // true
System.out.println(a instanceof Animal); // true
System.out.println(a instanceof Object); // true
}
}
A Dog is an Animal and also an Object, so all checks return true.
If the object is null, instanceof always returns false.
1
2
Dog d = null;
System.out.println(d instanceof Dog); // false
Use Case | Description |
---|---|
Type checking before casting | Prevents ClassCastException |
Polymorphic method logic | Different actions based on object type |
Runtime verification of class types | Helps debug or validate dynamic object assignments |
You can use instanceof to check if an object implements an interface:
1
2
3
4
5
6
7
8
9
10
11
interface Pet {}
class Cat implements Pet {}
public class Main {
public static void main(String[] args) {
Pet p = new Cat();
System.out.println(p instanceof Cat); // true
System.out.println(p instanceof Pet); // true
}
}
Since Java 16, instanceof supports pattern matching, which simplifies syntax:
1
2
3
if (obj instanceof Dog d) {
d.bark(); // No cast needed
}
This avoids explicit casting and is type-safe.
Overuse of instanceof may signal bad object-oriented design. Prefer polymorphism:
[NO] Instead of:
1
2
3
if (shape instanceof Circle) {
// special logic
}
[Yes] Use method overriding:
1
shape.draw();
Let each subclass define its own behavior.
In Java, casting is used to convert one object reference to another type—typically between classes in the same inheritance hierarchy. It is essential when working with polymorphism.
There are two main types:
Type | Description | Syntax |
---|---|---|
Upcasting | Child → Parent | Implicit |
Downcasting | Parent → Child | Explicit (must cast) |
Assigning a subclass object to a superclass reference.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Animal {
void makeSound() { System.out.println("Some sound"); }
}
class Dog extends Animal {
void bark() { System.out.println("Bark!"); }
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
Animal a = dog; // Upcasting
a.makeSound(); // OK
// a.bark(); // Not accessible
}
}
Upcasting is always safe. The reference type (Animal) controls accessible methods.
Assigning a superclass reference to a subclass type. Requires explicit casting and is only safe if the object is really an instance of the subclass.
1
2
3
Animal a = new Dog(); // Upcast
Dog d = (Dog) a; // Downcast
d.bark(); // Now accessible
Unsafe Downcasting:
1
2
Animal a = new Animal();
Dog d = (Dog) a; // ClassCastException at runtime!
instanceof
Always check type before downcasting to avoid runtime errors:
1
2
3
4
5
6
if (a instanceof Dog) {
Dog d = (Dog) a;
d.bark();
} else {
System.out.println("Not a Dog");
}
1
2
Animal a = new Animal();
Cat c = (Cat) a; // Compiles, but runtime error!
This throws a ClassCastException because a is not actually a Cat.