UNIT II - JAVA-Inheritance_part
UNIT II - JAVA-Inheritance_part
Inheritance: Basics, Using super, creating a multi level hierarchy, when constructors are
executed, method overriding, polymorphism - dynamic method dispatch, using abstract class,
final with Inheritance, object class.
Inheritance Concept
The inheritance is a very useful and powerful concept of object-oriented programming. In java,
using the inheritance concept, we can use the existing features of one class in another class.
The inheritance provides a great advantage called code re-usability. With the help of code re-
usability, the commonly used code in an application need not be written again and again.
1
Inheritance Basics
In inheritance, we use the terms like parent class, child class, base class, derived class,
superclass, and subclass.
The Parent class is the class which provides features to another class. The parent class is also
known as Base class or Superclass.
The Child class is the class which receives features from another class. The child class is also
known as the Derived Class or Subclass.
In the inheritance, the child class acquires the features from its parent class. But the parent class
never acquires the features from its child class.
2
The java programming language does not support multiple inheritance type. However, it
provides an alternate with the concept of interfaces.
In a java programming language, a class extends only one class. Extending multiple classes is
not allowed in java.
Let's look at individual inheritance types and how they get implemented in java with an
example.
4
Multi-level Inheritance in java
In this type of inheritance, the child class derives from a class which already derived from
another class. Look at the following example java code.
5
Hierarchical Inheritance in java
In this type of inheritance, two or more child classes derive from one parent class. Look at the
following example java code.
Example
class ParentClass{
int a;
void setData(int a) {
this.a = a;
}
}
6
class ChildClass extends ParentClass{
void showData() {
System.out.println("Inside ChildClass!");
System.out.println("Value of a is " + a);
}
}
class ChildClassToo extends ParentClass{
void display() {
System.out.println("Inside ChildClassToo!");
System.out.println("Value of a is " + a);
}
}
public class HierarchicalInheritance {
7
Hybrid Inheritance in java
The hybrid inheritance is the combination of more than one type of inheritance. We may use
any combination as a single with multiple inheritances, multi-level with multiple inheritances,
etc.,
8
Java super
The super keyword in Java is used in subclasses to access superclass members
(attributes, constructors and methods).
Before we learn about the super keyword, make sure to know about Java inheritance.
9
class Animal {
// overridden method
public void display(){
System.out.println("I am an animal");
}
}
// overriding method
@Override
public void display(){
System.out.println("I am a dog");
}
class Main {
public static void main(String[] args) {
Dog dog1 = new Dog();
dog1.printMessage();
}
}
Run Code
Output
I am a dog
In this example, by making an object dog1 of Dog class, we can call its method
printMessage() which then executes the display() statement.
10
Since display() is defined in both the classes, the method of subclass Dog overrides
the method of superclass Animal. Hence, the display() of the subclass is called.
// overridden method
public void display(){
System.out.println("I am an animal");
}
}
// overriding method
@Override
public void display(){
System.out.println("I am a dog");
}
11
// this calls overriding method
display();
class Main {
public static void main(String[] args) {
Dog dog1 = new Dog();
dog1.printMessage();
}
}
Run Code
Output
I am a dog
I am an animal
Here, how the above program works.
12
2. Access Attributes of the Superclass
The superclass and subclass can have attributes with the same name. We use
the super keyword to access the attribute of the superclass.
Example 3: Access superclass attribute
class Animal {
protected String type="animal";
}
class Main {
public static void main(String[] args) {
Dog dog1 = new Dog();
dog1.printType();
}
}
Run Code
Output:
I am a mammal
I am an animal
In this example, we have defined the same instance field type in both the
superclass Animal and the subclass Dog.
13
Hence, System.out.println("I am a " + type); prints I am a mammal.
And, System.out.println("I am an " + super.type); prints I am an
animal .
System.out.println("I am a dog");
}
14
}
class Main {
public static void main(String[] args) {
Dog dog1 = new Dog();
}
}
Run Code
Output
I am an animal
I am a dog
The flow of the program then returns back to the subclass constructor and executes
the remaining statements. Thus, I am a dog will be printed.
15
However, using super() is not compulsory. Even if super() is not used in the subclass
constructor, the compiler implicitly calls the default constructor of the superclass.
So, why use redundant code if the compiler automatically invokes super()?
It is required if the parameterized constructor (a constructor that takes
arguments) of the superclass has to be called from the subclass constructor.
The parameterized super() must always be the first statement in the body of the
constructor of the subclass, otherwise, we get a compilation error.
// parameterized constructor
Animal (String type) {
System.out.println("Type: "+type);
}
}
// default constructor
Dog() {
System.out.println("I am a dog");
}
}
class Main {
public static void main(String[] args) {
Dog dog1 = new Dog();
}
}
16
Run Code
Output
Type: Animal
I am a dogThe compiler can automatically call the no-arg constructor. However,
it cannot call parameterized constructors.
17
A constructor in Java is similar to a method with a few differences. Constructor has the same
name as the class name. A constructor doesn't have a return type.
A Java program will automatically create a constructor if it is not already defined in the
program. It is executed when an instance of the class is created.
1. Default constructor
2. Parameterized constructor
ExOrderSingleInh.java
/* Parent Class */
class ParentClass
{
/* Constructor */
ParentClass()
{
System.out.println("ParentClass constructor executed.");
}
}
/* Child Class */
class ChildClass extends ParentClass
{
/* Constructor */
ChildClass()
{
System.out.println("ChildClass constructor executed.");
}
18
}
Output:
In the above code, after creating an instance of ChildClass the ParentClass constructor is
invoked first and then the ChildClass.
ExOrderMultilevel.java
class College
{
/* Constructor */
College()
{
System.out.println("College constructor executed");
}
}
19
/* Constructor */
Student()
{
System.out.println("Student constructor executed");
}
}
public class ExOrderMultilevel
{
/* Driver Code */
public static void main(String ar[])
{
/* Create instance of Student class */
System.out.println("Order of constructor execution in Multilevel inheritance...");
new Student();
}
}
Output:
In the above code, an instance of Student class is created and it invokes the constructors
of College, Department and Student accordingly.
ExecutionOrder.java
20
public static void main(String ar[])
{
/* Create instance of the class */
System.out.println("Order of constructor execution...");
ExecutionOrder obj = new ExecutionOrder();
}
}
Output:
In the above code, the parameterized constructor is called first even when the default
constructor is called while object creation. It happens because this keyword is used as the first
line of the default constructor.
OrderofExecution4.java
/* Parent Class */
class ParentClass
{
int a;
ParentClass(int x)
{
a = x;
}
}
/* Child Class */
class ChildClass extends ParentClass
{
int b;
ChildClass(int x, int y)
{
/* Accessing ParentClass Constructor */
super(x);
b = y;
}
/* Method to show value of a and b */
void Show()
{
System.out.println("Value of a : "+a+"\nValue of b : "+b);
}
21
}
Output:
In the above code, the ChildClass calls the ParentClass constructor using a super keyword
that determines the order of execution of constructors.
Overriding in Java
If you’re a software engineer or developer preparing for a tech interview, and Java is your
preferred programming language, brushing up on the basic concepts will help you solve
problems with more ease. We know that Java is a high-level object-oriented programming
language. It offers many object-oriented properties. Overriding is one of the important features
in Java. In this article, we’ll review what overriding is and how it works:
22
What Is Overriding in Java?
In Java, declaring a method in a subclass that is already present in a parent class is
called method overriding. The main purpose of having overridden methods in the child is
having a different implementation for a method that is present in the parent class.
• Overriding method: The method in child class that is the same as a method in the parent class.
• Overridden method: The method in the parent class that is overridden by the child class
method.
Method overloading allows more than one method in a class to have the same name with
different parameters. Basically, we can create multiple methods with the same name in the
same class. However, each method works differently. It makes the program easier to read
(readable).
Here’s a summary of the key differences between overriding and overloading in Java:
23
Rules for Java Method Overriding
• Method name, its function parameters, and the return type of the overriding method and
overridden method must be the same.
• The access modifier of an overriding method cannot be more stringent than the access modifier
of an overridden method.
• Static, Private, and Final methods cannot be overridden because of their scope.
• If the class extends an abstract class or implements an interface, it must override all of the
abstract methods, provided the class itself is not abstract.
In the example above, the program will be compiled because the class Topic has its
method teach. Therefore, at the time of execution, it carries on a specific path to the given
object.
Code:
// Class Java
class Java {
// method teach which is overridden method here
24
public void teach() {
System.out.println("Topics in Java");
}
}
// Class Topic
class Topic extends Java {
// method teach which is overriding method here
public void teach() {
System.out.println("Individual topic");
}
}
class Overriding1 {
public static void main(String args[]) {
Java a = new Java(); // Java reference and object
Java b = new Topic(); // Java reference but Topic object
a.teach(); // runs the method in Java class
b.teach(); // runs the method in Topic class
}
}
Output:
Topics in Java
Individual topic
In method overriding, during method call in the main function, which method should
be executed (child class or parent class) is determined at runtime by the object type.
The process where the call to the overridden method is resolved at runtime is called
dynamic method dispatch.
So, we can call the overridden method by using the super keyword.
Code:
// Class Java
class Java {
// method teach which is overridden method here
25
public void teach() {
System.out.println("Topics in Java");
}
}
// Class Topic
class Topic extends Java {
// method teach which is overriding method here
public void teach() {
// this will call teach method of Java Class
super.teach();
System.out.println("Individual Topic");
}
}
class Main {
public static void main(String args[]) {
Java a = new Java(); // Java reference and object
Java b = new Topic(); // Java reference but Topic object
Topics in Java
Topics in Java
Individual Topic
There are some unusual ways to prevent method overriding in Java. Though the final modifier
is only for that purpose, we can use the private keyword to prevent method overriding. In order
to override a method, the class must be extensible. If we make the constructor of the parent
class private, it is impossible to extend that class because its constructor will not be accessible
in the subclass, which the sub-class constructor automatically invokes. Hence, it is not possible
to override any method from that class.
No. We cannot override constructors in Java because they are not inherited. We can overload
constructs, but we cannot override them. Overriding always happens in the child class, and
since constructors are not inherited, and their name is always the same as the class name, it is
not possible to override them in Java.
26
In the case of static methods, there won't be any runtime polymorphism. So, static methods
cannot be overridden. However, if a child class has a defined static method with a similar
signature as the static method of a parent class, then the method in the parent class will be
hidden by the method in the child class.
Polymorphism in Java
What is Polymorphism in Java?
Polymorphism in Java is the task that performs a single action in different ways. So, languages
that do not support polymorphism are not ‘Object-Oriented Languages’, but ‘Object-Based
Languages’. Ada, for instance, is one such language. Since Java supports polymorphism, it
is an Object-Oriented Language.
Polymorphism occurs when there is inheritance, i.e., many classes are related.
Inheritance is a powerful feature in Java. Java Inheritance lets one class acquire the properties
and attributes of another class. Polymorphism in Java allows us to use these inherited properties
to perform different tasks. Thus, allowing us to achieve the same action in many different ways.
What is Polymorphism?
The derivation of the word Polymorphism is from two different Greek words- poly and morphs.
“Poly” means numerous, and “Morphs” means forms. So, polymorphism means innumerable
forms. Polymorphism, therefore, is one of the most significant features of Object-Oriented
Programming.
A superclass named “Shapes” has a method called “area()”. Subclasses of “Shapes” can be
“Triangle”, “circle”, “Rectangle”, etc. Each subclass has its way of calculating area. Using
Inheritance and Polymorphism means, the subclasses can use the “area()” method to find the
area’s formula for that shape.
class Shapes {
public void area() {
System.out.println("The formula for area of ");
}
}
class Triangle extends Shapes {
public void area() {
System.out.println("Triangle is ½ * base * height ");
}
}
class Circle extends Shapes {
public void area() {
System.out.println("Circle is 3.14 * radius * radius ");
}
27
}
class Main {
public static void main(String[] args) {
Shapes myShape = new Shapes(); // Create a Shapes object
Shapes myTriangle = new Triangle(); // Create a Triangle object
Shapes myCircle = new Circle(); // Create a Circle object
myShape.area();
myTriangle.area();
myShape.area();
myCircle.area();
}
}
Output:
The formula for the area of the Triangle is 1/2 * base * height
The formula for the area of the Circle is 3.14 * radius * radius
class Shape {
public void draw() {
System.out.println("Drawing a shape");
}
}
class Main {
public static void main(String[] args) {
Shape s1 = new Circle();
Shape s2 = new Square();
28
In the main method, we create two instances of the Shape class, s1 and s2, which are actually
instances of the Circle and Square subclasses. When we call the draw() method on these
objects, the correct implementation is called based on the actual type of the object, this is run-
time polymorphism. The program will output: “Drawing a circle” and “Drawing a square”
In this example, the draw() method is overridden in the subclasses, and this allows for the
program to determine which method to use at runtime. This is known as runtime polymorphism
or dynamic polymorphism, Because at runtime the JVM determines the actual type of the object
and calls the corresponding method.
Types of Polymorphism
You can perform Polymorphism in Java via two different methods:
1. Method Overloading
2. Method Overriding
Method overloading is the process that can create multiple methods of the same name in the
same class, and all the methods work in different ways. Method overloading occurs when there
is more than one method of the same name in the class.
class Shapes {
public void area() {
System.out.println("Find area ");
}
public void area(int r) {
System.out.println("Circle area = "+3.14*r*r);
}
class Main {
public static void main(String[] args) {
Shapes myShape = new Shapes(); // Create a Shapes object
myShape.area();
myShape.area(5);
29
myShape.area(6.0,1.2);
myShape.area(6,2);
}
}
Output:
Find area
Circle area = 78.5
Triangle area=3.60
Rectangle area=12
Method overriding is the process when the subclass or a child class has the same method as
declared in the parent class.
1. Static/Compile-Time Polymorphism
2. Dynamic/Runtime Polymorphism
30
Method Overloading is when a class has multiple methods with the same name, but the number,
types, and order of parameters and the return type of the methods are different. Java allows the
user freedom to use the same name for various functions as long as it can distinguish between
them by the type and number of parameters. Check out some of the important questions on run
time polymorphism in java interview questions.
We will do addition in Java and understand the concept of compile time polymorphism using
subtract()
This is the basic concept of compile-time polymorphism in java where we can perform various
operations by using multiple methods having the same name.
Method Overriding is done when a child or a subclass has a method with the same name,
parameters, and return type as the parent or the superclass; then that function overrides the
31
function in the superclass. In simpler terms, if the subclass provides its definition to a method
already present in the superclass; then that function in the base class is said to be overridden.
Also, it should be noted that runtime polymorphism can only be achieved through functions
and not data members.
Overriding is done by using a reference variable of the superclass. The method to be called is
determined based on the object which is being referred to by the reference variable. This is also
known as Upcasting.
Upcasting takes place when the Parent class’s reference variable refers to the object of the child
class. For example:
class A{}
class B extends A{}
A a=new B(); //upcasting
Example 1:
In this example, we are creating one superclass Animal and three subclasses, Herbivores,
Carnivores, and Omnivores. Subclasses extend the superclass and override its eat() method.
We will call the eat() method by the reference variable of Parent class, i.e. Animal class. As it
refers to the base class object and the base class method overrides the superclass method; the
base class method is invoked at runtime. As Java Virtual Machine or the JVM and not the
compiler determines method invocation, it is, therefore, runtime polymorphism.
class Animal{
void eat(){
System.out.println("Animals Eat");
}
}
class herbivores extends Animal{
void eat(){
System.out.println("Herbivores Eat Plants");
}
}
class omnivores extends Animal{
void eat(){
System.out.println("Omnivores Eat Plants and meat");
}
}
class carnivores extends Animal{
void eat(){
System.out.println("Carnivores Eat meat");
}
}
32
class main{
public static void main(String args[]){
Animal A = new Animal();
Animal h = new herbivores(); //upcasting
Animal o = new omnivores(); //upcasting
Animal c = new carnivores(); //upcasting
A.eat();
h.eat();
o.eat();
c.eat();
}
}
Output:
Animals eat
Herbivores Eat Plants
Omnivores Eat Plants and meat
Carnivores eat meat
Example 2:
In this example, we are creating one superclass Hillstations and three subclasses Manali,
Mussoorie, Gulmarg. Subclasses extend the superclass and override its location() and
famousfor() method. We will call the location() and famousfor() method by the Parent class’,
i.e. Hillstations class. As it refers to the base class object and the base class method overrides
the superclass method; the base class method is invoked at runtime. Also, as Java Virtual
Machine or the JVM and not the compiler determines method invocation, it is runtime
polymorphism.
class Hillstations{
void location(){
System.out.println("Location is:");
}
void famousfor(){
System.out.println("Famous for:");
}
}
class Manali extends Hillstations {
void location(){
System.out.println("Manali is in Himachal Pradesh");
}
void famousfor(){
System.out.println("It is Famous for Hadimba Temple and adventure sports");
}
}
class Mussoorie extends Hillstations {
void location(){
System.out.println("Mussoorie is in Uttarakhand");
33
}
void famousfor(){
System.out.println("It is Famous for education institutions");
}
}
class Gulmarg extends Hillstations {
void location(){
System.out.println("Gulmarg is in J&K");
}
void famousfor(){
System.out.println("It is Famous for skiing");
}
}
class main{
public static void main(String args[]){
Hillstations A = new Hillstations();
Hillstations M = new Manali();
A.location();
A.famousfor();
M.location();
M.famousfor();
Mu.location();
Mu.famousfor();
G.location();
G.famousfor();
}
}
Output:
Location is:
Famous for:
Manali is in Himachal Pradesh
It is Famous for Hadimba Temple and adventure sports
Mussoorie is in Uttarakhand
It is Famous for education institutions
Gulmarg is in J&K
It is Famous for skiing
We will create two classes Car and Innova, Innova class will extend the car class and will
override its run() method.
34
class Car
{
void run()
{
System.out.println(“ running”);
}
}
class innova extends Car
{
void run();
{
System.out.println(“ running fast at 120km”);
}
public static void main(String args[])
{
Car c = new innova();
c.run();
}
}
The output of the following program will be;
Running fast at 120 km.
Another example for run-time polymorphism in Java
Now, let us check if we can achieve runtime polymorphism via data members.
class car
{
int speedlimit = 125;
}
class innova extends car
{
int speedlimit = 135;
public static void main(String args[])
{
car obj = new innova();
System.out.println(obj.speedlimit);
}
The output of the following program will be :
125
This clearly implies we can’t achieve Runtime polymorphism via data members. In short, a method is
overridden, not the data members.
Runtime polymorphism with multilevel inheritance
class grandfather
{
void swim()
{
System.out.println(“ Swimming”);
}
}
class father extends grandfather
{
void swim()
{
System.out.println(“ Swimming in river”);
}
35
}
class son extends father
{
void swim()
{
System.out.println(“ Swimming in pool”);
}
public static void main(String args[])
{
grandfather f1,f2,f3;
f1 =new grandfather();
f2 = new father();
f3 = new son();
f1.swim();
f2.swim();
f3.swim():
}
}
The output of the following program will be:
Swimming, Swimming in river, Swimming in pool
Another runtime polymorphism with multilevel inheritance example
class soundAnimal
{
public void Sound()
{
System.out.println("Different sounds of animal"); }
}
class buffalo extends soundAnimal
{
public void Sound()
{
System.out.println("The buffalo sound- gho,gho"); }
}
class snake extends soundAnimal
{
public void Sound()
{
System.out.println("The snake sound- his,his"); }
}
class tiger extends soundAnimal
{
public void Sound()
{
System.out.println("The tiger sounds- roooo, rooo"); }
}
public class Animal Main
{
public static void main(String[] args)
{
soundAnimal Animal = new soundAnimal(); soundAnimal buffalo = new buffalo();
soundAnimal snake = new snake();
soundAnimal tiger = new tiger();
36
Animal.Sound();
buffalo.Sound();
snake.Sound();
tiger.Sound();
}
}
The output of the following program will be;
The buffalo sound- gho,gho
The snake sound- his,his
The tiger sound- roooo,roooo
Polymorphic Subtypes
Subtype basically means that a subtype can serve as another type’s subtype, sounds a bit
complicated?
Assuming we have to draw some arbitrary shapes, we can introduce a class named ‘shape’ with
a draw() method. By overriding draw() with other subclasses such as circle, square, rectangle,
trapezium, etc we will introduce an array of type ‘shape’ whose elements store references will
refer to ‘shape’ subclass references. Next time, we will call draw(), all shapes instances draw
() method will be called.
This Subtype polymorphism generally relies on upcasting and late binding. A casting where
you cast up the inheritance hierarchy from subtype to a supertype is termed upcasting.
To call non-final instance methods we use late binding. In short, a compiler should not perform
any argument checks, type checks, method calls, etc, and leave everything on the runtime.
37
A single variable can be used to store multiple data values. The value of a variable you inherit
from the superclass into the subclass can be changed without changing that variable’s value in
the superclass; or any other subclasses.
With lesser lines of code, it becomes easier for the programmer to debug the code.
Characteristics of Polymorphism
Polymorphism has many other characteristics other than Method Overloading and Method
Overriding. They include:
Coercion
Internal Operator Overloading
Polymorphic Variables or Parameters
1. Coercion
Coercion deals with implicitly converting one type of object into a new object of a different
kind. Also, this is done automatically to prevent type errors in the code.
Programming languages such as C, java, etc support the conversion of value from one data
type to another data type. Data type conversions are of two types, i.e., implicit and explicit.
Implicit type conversion is automatically done in the program and this type of conversion is
also termed coercion.
For example, if an operand is an integer and another one is in float, the compiler implicitly
converts the integer into float value to avoid type error.
Example:
class coercion {
}
}
Output:
109.9
happy5
38
public static void main(String[] args) {
String s = "happy";
String s1 = "world";
int x=5;
int y=10;
System.out.println(s+s1);
System.out.println(x+y);
}
}
Output :
happyworld
15
Similarly, operators like! &, and | are also in the overload position for logical and bitwise
operations. In both of these cases, the type of argument will decide how the operator will
interpret.
3. Polymorphic Variables or Parameters
In Java, the object or instance variables represent the polymorphic variables. This is because
any object variables of a class can have an IS-A relationship with their own classes and
subclasses.
The Polymorphic Variable is a variable that can hold values of different types during the time
of execution.
Parametric polymorphism specifies that while class declaration, a field name can associate
with different types, and a method name can associate with different parameters and return
types.
For example:
class Shape
{
public void display()
{
System.out.println("A Shape.");
}
}
class Triangle extends Shape
{
public void display()
{
System.out.println("I am a triangle.");
}
}
class Main{
public static void main(String[] args)
{
Shape obj;
obj = new Shape();
obj.display();
obj = new Triangle();
39
obj.display();
}
}
Output:
A Shape.
I am a triangle.
Here, the obj object is a polymorphic variable. This is because the superclass’s same object
refers to the parent class (Shape) and the child class (Triangle).
Example,
In downcasting, we narrow the type of objects, which means we are converting common type
to individual type.
Here we are casting common type to an individual type, superclass to subclass which is not
possible directly in java.
We explicitly tell the compiler what the runtime type of the object is.
40
This architectural problem is termed as a fragile base class problem in object-oriented
programming systems and language.
Basically, the reason for the fragile base problem is that the developer of the base class has no
idea of the subclass design. There is no solution yet for this problem.
41