1. What is inheritance and why it is need?
In Java, inheritance is a mechanism that allows a class (called the subclass or child class) to acquire
properties (fields) and behaviors (methods) of another class (called the superclass or parent class).
This is one of the four pillars of Object-Oriented Programming (OOP) in Java, alongside
Encapsulation, Polymorphism, and Abstraction.
Why Inheritance is Needed in Java:
1. Code Reusability: Inheritance allows subclasses to reuse methods and fields from the superclass,
avoiding the need to write redundant code.
2. Simplifies Code Maintenance: Any changes made to the superclass (like bug fixes or updates)
are automatically reflected in all the subclasses, reducing the amount of code you need to
change.
3. Hierarchical Classification: Inheritance helps to create a class hierarchy, reflecting real-world
relationships (e.g., an "Employee" class can be a subclass of a "Person" class).
4. Polymorphism: Inheritance enables polymorphism, allowing objects of different classes to be
treated as instances of a common superclass, which simplifies the code and allows more flexible
behavior.
5. Extending Functionality: Subclasses can extend the functionality of a superclass by adding their
own methods or overriding the superclass methods to provide more specialized behavior.
Syntax of Inheritance in Java:
• The extends keyword is used to inherit from a superclass.
Example of Inheritance in Java:
// Superclass or Parent Class
class Animal {
void sound() {
System.out.println("Animal makes a sound");
// Subclass or Child Class
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
class Cat extends Animal {
// Inherits the sound method from Animal without overriding
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
myDog.sound(); // Output: Dog barks
Animal myCat = new Cat();
myCat.sound(); // Output: Animal makes a sound
Explanation:
1. Superclass Animal: The Animal class has a method sound() that prints a generic message.
2. Subclass Dog: The Dog class extends the Animal class and overrides the sound() method to give
a more specific implementation.
3. Subclass Cat: The Cat class inherits the sound() method from the Animal class without changing
it.
4. Polymorphism: The myDog and myCat variables are of type Animal but hold objects of Dog and
Cat respectively. Even though the variable type is Animal, the correct version of sound() is called
based on the actual object type (i.e., Dog or Cat).
Key Points:
• extends keyword: This is used to indicate that a class is inheriting from another class.
• Method Overriding: A subclass can modify the behavior of a superclass method by providing its
own implementation (using the @Override annotation).
• Single Inheritance: In Java, a class can inherit from only one superclass (single inheritance),
though it can implement multiple interfaces.
Limitations of Inheritance in Java:
• Single Inheritance: Java does not support multiple inheritance (a class cannot extend more than
one class).
• Method Visibility: The inherited methods can only be used if they are accessible to the subclass
(i.e., they should be public or protected, or have package-private access within the same
package).
Overall, inheritance in Java helps achieve modular and maintainable code by reusing existing
functionality, creating class hierarchies, and providing flexibility through polymorphism.
2. State the types of inheritance and explain them with example.
In Java, inheritance allows a class to acquire properties and behaviors from another class. There are
different types of inheritance that can be used depending on how classes relate to each other. The
following are the main types of inheritance in Java:
1. Single Inheritance
Single inheritance occurs when a class inherits from only one superclass. This is the simplest form of
inheritance.
Example:
// Superclass (Parent class)
class Animal {
void sound() {
System.out.println("Animal makes a sound");
// Subclass (Child class) that inherits from Animal
class Dog extends Animal {
void sound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.sound(); // Output: Dog barks
• Explanation: The Dog class inherits from the Animal class and can override the sound() method
to provide its own implementation.
2. Multilevel Inheritance
Multilevel inheritance occurs when a class is derived from another class, which is also derived from
another class, forming a chain.
Example:
// Grandparent Class (Base class)
class Animal {
void sound() {
System.out.println("Animal makes a sound");
// Parent Class inherits from Animal
class Dog extends Animal {
void sound() {
System.out.println("Dog barks");
// Child Class inherits from Dog
class Puppy extends Dog {
void sound() {
System.out.println("Puppy yelps");
public class Main {
public static void main(String[] args) {
Puppy puppy = new Puppy();
puppy.sound(); // Output: Puppy yelps
• Explanation: The Puppy class inherits from the Dog class, which in turn inherits from the Animal
class. Each class can add or modify methods in the chain.
3. Hierarchical Inheritance
In hierarchical inheritance, multiple subclasses inherit from a single superclass. The common properties
and behaviors from the superclass are shared among all subclasses.
Example:
// Superclass
class Animal {
void sound() {
System.out.println("Animal makes a sound");
// Subclass 1
class Dog extends Animal {
void sound() {
System.out.println("Dog barks");
}
// Subclass 2
class Cat extends Animal {
void sound() {
System.out.println("Cat meows");
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.sound(); // Output: Dog barks
Cat cat = new Cat();
cat.sound(); // Output: Cat meows
• Explanation: Both Dog and Cat inherit from the same superclass Animal, so they share the ability
to override the sound() method, but each class can provide its own specific implementation.
4. Multiple Inheritance (Through Interfaces)
Java does not support multiple inheritance with classes (i.e., a class cannot inherit from more than one
class). However, Java supports multiple inheritance through interfaces. A class can implement multiple
interfaces, inheriting the methods declared in those interfaces.
Example:
// Interface 1
interface Animal {
void sound();
}
// Interface 2
interface Swimmer {
void swim();
// Class implementing both interfaces
class Dog implements Animal, Swimmer {
public void sound() {
System.out.println("Dog barks");
public void swim() {
System.out.println("Dog swims");
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.sound(); // Output: Dog barks
dog.swim(); // Output: Dog swims
• Explanation: The Dog class implements both the Animal and Swimmer interfaces, thus inheriting
methods from both interfaces. This is a form of multiple inheritance, where a class can inherit
behavior from more than one source (interfaces).
5. Hybrid Inheritance (Combination of Types)
Hybrid inheritance is a combination of two or more types of inheritance, typically involving classes and
interfaces. Java does not directly support hybrid inheritance with classes (because it avoids multiple
inheritance of classes), but it can achieve hybrid inheritance by using both classes and interfaces.
Example:
// Interface 1
interface Animal {
void sound();
// Interface 2
interface Swimmer {
void swim();
// Parent Class
class Mammal {
void walk() {
System.out.println("Mammal walks");
// Child Class implementing two interfaces and extending a class
class Dog extends Mammal implements Animal, Swimmer {
public void sound() {
System.out.println("Dog barks");
public void swim() {
System.out.println("Dog swims");
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.sound(); // Output: Dog barks
dog.swim(); // Output: Dog swims
dog.walk(); // Output: Mammal walks
• Explanation: The Dog class extends Mammal (single inheritance), and implements two interfaces
(Animal and Swimmer) to inherit methods from both. This is an example of hybrid inheritance,
where the class combines multiple inheritance techniques.
3. Why Multiple inheritance through classes is not supported in Java?
Multiple inheritance through classes is not supported in Java primarily due to ambiguity and
maintenance issues that can arise from such a mechanism. Let's break down the reasons in detail:
1. The Diamond Problem
The diamond problem is one of the main reasons why Java does not support multiple inheritance with
classes. It occurs when a class inherits from two classes that have a common ancestor. This creates
ambiguity because if both parent classes have a method or field with the same name, it’s unclear which
one the child class should inherit.
Example:
class A {
void greet() {
System.out.println("Hello from class A");
class B extends A {
void greet() {
System.out.println("Hello from class B");
class C extends A {
void greet() {
System.out.println("Hello from class C");
class D extends B, C { // Error: Cannot inherit from multiple classes
void greet() {
System.out.println("Hello from class D");
In this case, the class D is trying to inherit from both B and C. Both B and C override the greet() method
from A, leading to a situation where it's unclear which greet() method the class D should inherit. This is
problematic for both the compiler and the programmer, leading to confusion and bugs.
2. Ambiguity and Method Resolution
If a class could inherit from multiple classes, and those classes define methods with the same name, the
Java compiler would not know which method to call when invoking the method on the subclass object.
This creates ambiguity in method resolution, leading to errors or unexpected behavior.
Example of Ambiguity:
class A {
void show() {
System.out.println("A's show method");
}
class B {
void show() {
System.out.println("B's show method");
class C extends A, B { // Error: Cannot inherit from multiple classes
// Which show() method should be called?
In this case, if class C inherits from both A and B, there is ambiguity about which show() method should
be invoked. Java avoids this situation by not allowing multiple inheritance of classes.
3. Increased Complexity
Allowing multiple inheritance can increase the complexity of the Java language. It would introduce the
need for more sophisticated mechanisms for method resolution and conflict resolution, making the
language harder to learn, understand, and maintain. By disallowing multiple inheritance, Java keeps the
object-oriented model simple and consistent.
4. Favoring Interfaces for Multiple Inheritance
Instead of supporting multiple inheritance of classes, Java uses interfaces to achieve a form of multiple
inheritance. A class can implement multiple interfaces, which allows it to inherit abstract method
signatures from multiple sources without the complications of class inheritance.
Example using interfaces:
interface Animal {
void sound();
interface Swimmer {
void swim();
class Dog implements Animal, Swimmer {
public void sound() {
System.out.println("Dog barks");
public void swim() {
System.out.println("Dog swims");
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.sound(); // Output: Dog barks
dog.swim(); // Output: Dog swims
In this example, Dog implements both Animal and Swimmer interfaces, enabling it to inherit behaviors
from both, but without the complications of multiple inheritance through classes. Interfaces allow for
multiple inheritance of method signatures without introducing method resolution issues.
5. Design Philosophy
Java was designed to be a simple, object-oriented language. Multiple inheritance through classes can
lead to complex, hard-to-manage relationships between objects. By disallowing multiple inheritance of
classes, Java promotes clearer class hierarchies, better code maintainability, and easier debugging. This
design decision avoids potential pitfalls and allows developers to focus on cleaner, more understandable
code.
Key Takeaways:
• Diamond Problem: Multiple inheritance can lead to ambiguity when two parent classes have
methods with the same name. This would create conflicts about which method to inherit.
• Method Resolution Issues: Inheritance from multiple classes can create problems with which
method gets invoked when there are conflicting method signatures.
• Increased Complexity: Allowing multiple inheritance increases language complexity, which Java
avoids in favor of simpler designs.
• Interfaces: Java allows multiple inheritance through interfaces instead, which solves many of
the issues of conflicting methods and ambiguity by enforcing method signatures but not
implementation.
Conclusion:
Java doesn't support multiple inheritance through classes because it introduces ambiguity, increases
complexity, and can lead to difficult-to-maintain code. Instead, Java promotes the use of interfaces to
allow a form of multiple inheritance while avoiding these problems.
4. Explain Method Overriding with suitable example.
Method Overriding in Java
Method Overriding in Java occurs when a subclass provides a specific implementation of a method that
is already defined in its superclass. In other words, the subclass redefines the method inherited from the
parent class, with the same method signature (name, return type, and parameters). This is a way to
customize or modify the behavior of a method in the subclass.
Key Points about Method Overriding:
1. Same Method Signature: The method in the subclass must have the same name, return type,
and parameters as the method in the superclass.
2. Access Level: The access level of the overridden method in the subclass should be the same or
more permissive than that in the superclass. For example, a public method in the superclass can
be overridden as public or protected in the subclass, but not as private.
3. Runtime Polymorphism: Method overriding is a key feature of runtime polymorphism, where
the method call is resolved at runtime depending on the object's type.
Why Use Method Overriding?
• It allows a subclass to modify or extend the behavior of a superclass method.
• It is essential for achieving polymorphism in Java, as it enables the correct method to be called
based on the actual object type.
Example of Method Overriding
// Superclass (Parent class)
class Animal {
// Method in the superclass
void sound() {
System.out.println("Animal makes a sound");
}
}
// Subclass (Child class) that overrides the sound() method
class Dog extends Animal {
// Method overriding in the subclass
@Override
void sound() {
System.out.println("Dog barks");
class Cat extends Animal {
// Method overriding in the subclass
@Override
void sound() {
System.out.println("Cat meows");
public class Main {
public static void main(String[] args) {
// Create objects of Animal, Dog, and Cat
Animal animal = new Animal(); // Superclass object
animal.sound(); // Output: Animal makes a sound
Animal dog = new Dog(); // Subclass object
dog.sound(); // Output: Dog barks (runtime polymorphism)
Animal cat = new Cat(); // Subclass object
cat.sound(); // Output: Cat meows (runtime polymorphism)
Explanation of the Example:
1. Superclass Animal:
o The sound() method is defined in the Animal class and provides a generic behavior:
"Animal makes a sound."
2. Subclass Dog:
o The Dog class overrides the sound() method to provide its own implementation: "Dog
barks."
o The @Override annotation is optional but recommended, as it helps catch errors at
compile time if the method signature doesn't match the one in the superclass.
3. Subclass Cat:
o Similarly, the Cat class overrides the sound() method to print: "Cat meows."
4. Polymorphism:
o In the main() method, we create objects of type Animal, but we assign them instances of
Dog and Cat (which are subclasses of Animal).
o When the sound() method is called, the version of the method in the subclass (either
Dog or Cat) is invoked, not the one in the Animal class. This is an example of runtime
polymorphism.
Output:
Animal makes a sound
Dog barks
Cat meows
How Method Overriding Works:
• When you call dog.sound(), the sound() method from the Dog class is executed, even though the
reference variable dog is of type Animal.
• Similarly, cat.sound() calls the overridden sound() method in the Cat class.
Rules for Method Overriding:
1. Method Signature: The method in the subclass must have the same name, return type, and
parameters as in the superclass.
2. Access Modifiers: The overriding method in the subclass cannot have a more restrictive access
modifier than the method in the superclass.
3. @Override Annotation: This annotation is used to indicate that a method is overriding a
superclass method. It is optional but highly recommended to prevent errors.
Conclusion:
Method overriding in Java allows subclasses to provide their own implementation of methods inherited
from a superclass. It is a fundamental feature for achieving polymorphism and allows objects to behave
according to their actual class type. By overriding methods, subclasses can modify or extend the
functionality of methods in the parent class while maintaining the same method signature.
5. Differentiate between Run time polymorphism and compile time
polymorphism.
Polymorphism is a fundamental concept in object-oriented programming (OOP) that allows objects to
behave in different ways based on their actual class type. In Java, polymorphism is divided into two
types: Runtime Polymorphism and Compile-time Polymorphism. Both are used to achieve flexibility in
the code, but they differ in terms of when the method to be executed is determined.
1. Compile-Time Polymorphism (also called Method Overloading)
Definition: Compile-time polymorphism occurs when the method to be executed is determined at
compile time. It is achieved through method overloading.
Key Characteristics:
• The method call is resolved at compile time by the compiler.
• Involves method overloading, where multiple methods with the same name but different
parameters exist in the same class.
• The method to be invoked is determined based on the number or types of arguments passed
during the method call.
Example:
class Calculator {
// Method Overloading (Compile-time polymorphism)
int add(int a, int b) {
return a + b;
double add(double a, double b) {
return a + b;
public class Main {
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println(calc.add(5, 10)); // Calls int add method
System.out.println(calc.add(5.5, 10.5)); // Calls double add method
Explanation:
• The add method is overloaded with two versions: one that accepts integers and another that
accepts doubles.
• The appropriate add method is selected by the compiler based on the method arguments
passed when called. The decision is made at compile time.
2. Runtime Polymorphism (also called Method Overriding)
Definition: Runtime polymorphism occurs when the method to be executed is determined at runtime. It
is achieved through method overriding in Java, where a subclass provides a specific implementation of a
method defined in its superclass.
Key Characteristics:
• The method call is resolved at runtime based on the object's actual type (not the reference
type).
• Involves method overriding, where a method in a superclass is redefined (overridden) in a
subclass with a different implementation.
• It enables dynamic method dispatch (the Java runtime decides which method to call).
Example:
class Animal {
void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
class Cat extends Animal {
@Override
void sound() {
System.out.println("Cat meows");
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Animal(); // Reference of type Animal
Animal myDog = new Dog(); // Reference of type Animal, but object of type Dog
Animal myCat = new Cat(); // Reference of type Animal, but object of type Cat
myAnimal.sound(); // Output: Animal makes a sound
myDog.sound(); // Output: Dog barks (runtime polymorphism)
myCat.sound(); // Output: Cat meows (runtime polymorphism)
Explanation:
• Even though the reference type is Animal, the actual object type (Dog or Cat) determines which
sound() method is called.
• The method is resolved at runtime, based on the actual object that the reference is pointing to
at the time of method invocation.
• This is runtime polymorphism.
Key Differences Between Runtime Polymorphism and Compile-Time Polymorphism
Aspect Runtime Polymorphism Compile-Time Polymorphism
Occurs when the method to be Occurs when the method to be invoked is
Definition
invoked is determined at runtime. determined at compile time.
Method Overriding (involves Method Overloading (same method
Achieved by
inheritance and interfaces). name, different parameters).
Dynamic binding (the method is Static binding (the method is bound at
Binding Type
bound at runtime). compile time).
The method is resolved based on the The method is resolved based on the
Method Resolution
actual object type (runtime). method signature (compile-time).
Use of @Override Required to indicate method
Not applicable.
Annotation overriding.
Slightly slower because method Faster since the method is resolved
Performance
resolution happens at runtime. during compilation.
Method Overriding (Dog overriding Method Overloading (add(int, int) and
Example
sound() method of Animal). add(double, double) in Calculator).
Runtime Polymorphism (Dynamic Compile-Time Polymorphism (Static
Polymorphism Type
method dispatch). method dispatch).
Conclusion:
• Runtime Polymorphism is more powerful and flexible, enabling you to override methods in
subclasses and choose the method implementation based on the object type at runtime. It is
mainly used to implement dynamic behavior and runtime decision-making.
• Compile-Time Polymorphism is simpler and involves method overloading, where the method to
call is determined based on the method signature during compilation. It is resolved at compile
time and doesn't offer the same flexibility as runtime polymorphism.