JAVA Module3 Notes
JAVA Module3 Notes
MODULE 3
Constructors Are Executed, Method Overriding, Dynamic Method Dispatch, Using Abstract
Classes, Using final with Inheritance, Local Variable Type Inference and Inheritance, The Object
Class.
Inheritance in Java
1. Inheritance
2. Types of Inheritance
3. Why multiple inheritance is not possible in Java in case of class?
Inheritance in Java is a mechanism in which one object acquires all the properties and behaviors
of a parent object. It is an important part of OOPs (Object Oriented programming system).
The idea behind inheritance in Java is that you can create new classes that are built upon existing
classes. When you inherit from an existing class, you can reuse methods and fields of the parent
class. Moreover, you can add new methods and fields in your current class also.
Inheritance represents the IS-A relationship which is also known as a parent-child relationship.
The extends keyword indicates that you are making a new class that derives from an existing
class. The meaning of "extends" is to increase the functionality.
In the terminology of Java, a class which is inherited is called a parent or superclass, and the new
class is called child or subclass.
As displayed in the above figure, Programmer is the subclass and Employee is the superclass. The
relationship between the two classes is Programmer IS-A Employee. It means that Programmer
is a type of Employee.
class Employee{
float salary=40000;
}
class Programmer extends Employee{
int bonus=10000;
public static void main(String args[]){
Programmer p=new Programmer();
[Link]("Programmer salary is:"+[Link]);
[Link]("Bonus of Programmer is:"+[Link]);
}
}
Test it Now
Programmer salary is:40000.0
Bonus of programmer is:10000
In the above example, Programmer object can access the field of own class as well as of Employee
class i.e. code reusability.
On the basis of class, there can be three types of inheritance in java: single, multilevel and
hierarchical.
In java programming, multiple and hybrid inheritance is supported through interface only. We will
learn about interfaces later.
When one class inherits multiple classes, it is known as multiple inheritance. For Example:
When a class inherits another class, it is known as a single inheritance. In the example given below,
Dog class inherits the Animal class, so there is the single inheritance.
File: [Link]
class Animal{
void eat(){[Link]("eating...");}
}
class Dog extends Animal{
void bark(){[Link]("barking...");}
}
class TestInheritance{
public static void main(String args[]){
Dog d=new Dog();
[Link]();
[Link]();
}}
Output:
barking...
eating...
When there is a chain of inheritance, it is known as multilevel inheritance. As you can see in the
example given below, BabyDog class inherits the Dog class which again inherits the Animal class,
so there is a multilevel inheritance.
File: [Link]
class Animal{
void eat(){[Link]("eating...");}
}
class Dog extends Animal{
void bark(){[Link]("barking...");}
}
class BabyDog extends Dog{
void weep(){[Link]("weeping...");}
}
class TestInheritance2{
public static void main(String args[]){
BabyDog d=new BabyDog();
[Link]();
[Link]();
[Link]();
}}
Output:
weeping...
barking...
eating...
When two or more classes inherits a single class, it is known as hierarchical inheritance. In the
example given below, Dog and Cat classes inherits the Animal class, so there is hierarchical
inheritance.
File: [Link]
class Animal{
void eat(){[Link]("eating...");}
}
class Dog extends Animal{
void bark(){[Link]("barking...");}
}
class Cat extends Animal{
void meow(){[Link]("meowing...");}
}
class TestInheritance3{
public static void main(String args[]){
Cat c=new Cat();
[Link]();
[Link]();
//[Link]();//[Link]
}}
Output:
meowing...
eating...
To reduce the complexity and simplify the language, multiple inheritance is not supported in java.
Consider a scenario where A, B, and C are three classes. The C class inherits A and B classes. If
A and B classes have the same method and you call it from child class object, there will be
ambiguity to call the method of A or B class.
Since compile-time errors are better than runtime errors, Java renders compile-time error if you
inherit 2 classes. So whether you have same method or different, there will be compile time error.
class A{
void msg(){[Link]("Hello");}
}
class B{
void msg(){[Link]("Welcome");}
}
class C extends A,B{//suppose if it were
The super keyword in Java is a reference variable which is used to refer immediate parent class
object.
Whenever you create the instance of subclass, an instance of parent class is created implicitly
which is referred by super reference variable.
class Animal{
String color="white";
[Link], Dept. of CSE, SJBIT Page 9
Object Oriented Programming with Java ****** 23CSO612
}
class Dog extends Animal{
String color="black";
void printColor(){
[Link](color);//prints color of Dog class
[Link]([Link]);//prints color of Animal class
}
}
class TestSuper1{
public static void main(String args[]){
Dog d=new Dog();
[Link]();
}}
Output:
black
white
In the above example, Animal and Dog both classes have a common property color. If we print
color property, it will print the color of current class by default. To access the parent property, we
need to use super keyword.
class Animal{
void eat(){[Link]("eating...");}
}
class Dog extends Animal{
void eat(){[Link]("eating bread...");}
void bark(){[Link]("barking...");}
void work(){
[Link]();
bark();
}
}
class TestSuper2{
public static void main(String args[]){
Dog d=new Dog();
[Link]();
}}
Output:
eating...
barking...
In the above example Animal and Dog both classes have eat() method if we call eat() method from
Dog class, it will call the eat() method of Dog class by default because priority is given to local.
class Animal{
Animal(){[Link]("animal is created");}
}
class Dog extends Animal{
Dog(){
super();
[Link]("dog is created");
}
}
class TestSuper3{
public static void main(String args[]){
Dog d=new Dog();
}}
Output:
animal is created
dog is created
Note: super() is added in each class constructor automatically by compiler if there is no super()
or this().
Another example of super keyword where super() is provided by the compiler implicitly.
class Animal{
Animal(){[Link]("animal is created");}
}
class Dog extends Animal{
Dog(){
[Link]("dog is created");
}
}
class TestSuper4{
public static void main(String args[]){
Dog d=new Dog();
}}
Output:
animal is created
dog is created
super example: real use
Let's see the real use of super keyword. Here, Emp class inherits Person class so all the properties
of Person will be inherited to Emp by default. To initialize all the property, we are using parent
class constructor from child class. In such way, we are reusing the parent class constructor.
class Person{
int id;
String name;
Person(int id,String name){
[Link]=id;
[Link]=name;
}
}
class Emp extends Person{
float salary;
Emp(int id,String name,float salary){
super(id,name);//reusing parent constructor
[Link]=salary;
}
void display(){[Link](id+" "+name+" "+salary);}
}
class TestSuper5{
public static void main(String[] args){
Emp e1=new Emp(1,"ankit",45000f);
[Link]();
}}
Output:
1 ankit 45000
Method Overriding
If subclass (child class) has the same method as declared in the parent class, it is known as method
overriding in Java.
In other words, If a subclass provides the specific implementation of the method that has been
3. Method overriding allows subclasses to reuse and build upon the functionality provided by
4. Subclasses can override methods to tailor them to their specific needs or to implement
5. Method overriding enables dynamic method dispatch, where the actual method
1. Same Method Name: The overriding method in the subclass must have the same name as
2. Same Parameters: The overriding method must have the same number and types of
parameters as the method in the superclass. This ensures compatibility and consistency
between the subclass and the superclass. This means that the subclass must inherit from
4. Same Return Type or Covariant Return Type: The return type of the overriding method
can be the same as the return type of the overridden method in the superclass, or it can be
a subtype of the return type in the superclass. This is known as the covariant return type,
introduced in Java 5.
5. Access Modifier Restrictions: The access modifier of the overriding method must be the
same as or less restrictive than the access modifier of the overridden method in the
as public or protected but not as private. Similarly, a method declared as protected in the
superclass can be overridden as protected or public but not as private. A method declared
7. No Static Methods: Static methods in Java are resolved at compile time and cannot be
overridden. Instead, they are hidden in the subclass if a method with the same signature is
Let's understand the problem that we may face in the program if we don't use method overriding.
[Link]
//class object.
class Vehicle{
[Link]();
Output:
Vehicle is running
Explanation
"Vehicle is running" is printed by the run() function of the Vehicle class. We construct an instance
of the Bike class and use it to invoke the run() method within the Bike class. As a result of Bike
deriving from Vehicle, the run() function of the Vehicle class is overridden in the Bike class,
resulting in the print "Vehicle is running" when the method is used on a Bike object. This
demonstrates how method overriding, in which the method specified in the subclass overrides the
method in the superclass with the identical signature, can result in polymorphic behaviour.
In this example, we have defined the run method in the subclass as defined in the parent class, but
it has some specific implementation. The method's name and parameters are the same, and there
[Link]
class Vehicle{
//defining a method
[Link]();//calling method
Output:
Explanation
A method in a subclass (Bike2) overrides the same method in its superclass (Vehicle), as this Java
program illustrates. The run() method in this example is shared by both types, but the Bike2 class
implements it differently, outputting "Bike is running safely." The overridden function in the Bike2
class gets executed when we create an instance of Bike2 and use the run() method on it, proving
that the implementation of the subclass takes precedence over the implementation of the
superclass. This demonstrates how Java's dynamic polymorphism feature allows methods with the
same signature to behave differently in various classes, even if they are part of the same inheritance
tree.
Consider a scenario where Bank is a class that provides functionality to get the rate of interest.
However, the rate of interest varies according to banks. For example, SBI, ICICI and AXIS banks
[Link]
class Bank{
class Test2{
Output:
Explanation
This Java programme uses a real-world scenario where three classes-SBI, ICICI, and AXIS-
override a method from their parent class, Bank, to demonstrate the idea of method overriding.
The getRateOfInterest() function of the Bank class yields 0. With their own implementation, each
of the child classes overrides this method: SBI returns 8, ICICI returns 7, and AXIS returns 9. Each
child class object is created in the Test2 class, and then each object's getRateOfInterest() method
is used to print out the corresponding interest rates for each bank. This illustrates how polymorphic
behaviour dependent on the type of object at runtime is made possible by method overriding, which
enables each subclass to give its own implementation of a method inherited from the superclass.
No, a static method cannot be overridden in Java. When a subclass defines a static method with
the same signature as a static method in its superclass, it is simply hiding the superclass method,
not overriding it. This means that the method invoked is determined at compile time based on the
reference type, not at runtime based on the object's type. Therefore, static methods do not exhibit
Because static methods in Java are linked to the class itself rather than any specific instance of the
class, we are unable to override them. Java's dynamic dispatch mechanism, which determines the
method to be called at runtime depending on the object's actual type, forms the foundation for
method overriding.
Static methods cannot be overridden in the same manner as instance methods since they are not
subject to dynamic dispatch because they are resolved at compile time based on the reference type
Furthermore, while instance methods are kept in the object's heap area and are specific to each
instance of the class, static methods are kept in the method region of the JVM's memory, which is
shared by all instances of the class. Static methods cannot be altered due to the basic differences
in their behaviour and memory allocation between instance and static methods.
No, because the Java main() method is designated as static, we are unable to override it. The main
function in Java is declared as public static void main(String[] args) and acts as the program's
starting point.
The method in question is part of the class itself, not any particular instance of the class, as
It is not possible to override the main method in a subclass since static methods are not overridable.
As the initial point of execution, each Java program must contain exactly one main method that
Purpose and Intent increase the readability of the implementation of the method
superclass.
polymorphism. polymorphism.
If you are overriding any method, overridden method (i.e. declared in subclass) must not be more
restrictive.
[Link]
class A{
[Link]();
Output:
Explanation
Class A declares a method called msg() with the protected access modifier in the provided Java
code. By extending class A, class Simple aims to replace the message() function with a default
access modifier. But because the default access modifier is more restricted than protected, this
leads to a compile-time error. When overriding a method in Java, the overridden method's access
level in the subclass needs to be at least as liberal as the method's access level in the superclass.
Thus, in order to fix the issue, either the class Simple method's access modifier-such as protected
or public-should be as liberal as protected, or the class A method should have a less permissive
Java, as an object-oriented programming language, supports one of the key features of OOP -
polymorphism. It allows objects to take on multiple forms, and one way it achieves this is through
a mechanism called dynamic method dispatch. The feature plays a crucial role in achieving
Polymorphism
Before delving into dynamic method dispatch, it is important to grasp the concept of
For example, if we have a superclass Animal and subclasses Dog and Cat, we can create an array
of Animal objects and store instances of both Dog and Cat in it. We can then iterate through the
array and call a method like makeSound() on each element, and the appropriate version of
class Animal {
void makeSound() {
@Override
void makeSound() {
[Link]("Bark");
@Override
void makeSound() {
[Link]("Meow");
[Link]();
In this example, we have created an array of Animal objects and populate it with instances of Dog
and Cat. When we call makeSound() on each element, the version defined in the subclass will be
Dynamic method dispatch or run-time polymorphism is the mechanism through which the correct
version of an overridden method is called at runtime. When a subclass overrides a method from its
superclass, the overridden method in the subclass is executed when called on an instance of the
In the previous example, when we call [Link]() in the loop, the appropriate
makeSound() method defined in either Dog or Cat is executed based on the actual type of the
object.
It is a powerful feature because it allows for flexibility in the way we write code. We can write
methods in the superclass that are common to all subclasses, and then have specific behavior
Dynamic method dispatch is particularly useful in scenarios where we want to write code that
operates on a general type but can be specialized by subclasses. It promotes code reusability and
For example, if we were building a game with different types of characters (for example, warriors,
mages, archers), we could have a Character superclass with the attack() method. Each specific
character type (warrior, mage, archer) would then override the attack() method with its own
implementation. It allows us to write code that can handle any type of character without knowing
Complete Java program that demonstrates dynamic method dispatch along with input and output.
[Link]
class Animal {
void makeSound() {
@Override
void makeSound() {
[Link]("Bark");
@Override
void makeSound() {
[Link]("Meow");
[Link]();
Output:
Bark
Meow
In the Main class, we have created an array of Animal objects called animals and populate it with
an instance of Dog and an instance of Cat. We then iterate through the animals array using a for-
each loop and call the makeSound() method on each element. Due to dynamic method dispatch,
the appropriate version of makeSound() from either Dog or Cat will be executed based on the
Dynamic method dispatch is a powerful feature of Java that enables polymorphism and promotes
code reusability and modularity. By allowing objects to take on multiple forms, Java provides a
Understanding dynamic method dispatch is essential for writing efficient and maintainable code
in Java, especially in scenarios where you want to work with objects at a higher level of abstraction.
master.
A class which is declared with the abstract keyword is known as an abstract class in Java. It can
have abstract and non-abstract methods (method with the body).
Before learning the Java abstract class, let's understand the abstraction in Java first.
Abstraction in Java
Abstraction is a process of hiding the implementation details and showing only functionality to
the user.
Another way, it shows only essential things to the user and hides the internal details, for example,
sending SMS where you type the text and send the message. You don't know the internal
processing about the message delivery.
Abstraction lets you focus on what the object does instead of how it does it.
A class which is declared as abstract is known as an abstract class. It can have abstract and non-
abstract methods. It needs to be extended and its method implemented. It cannot be instantiated.
Points to Remember
A method which is declared as abstract and does not have implementation is known as an abstract
method.
In this example, Bike is an abstract class that contains only one abstract method run. Its
implementation is provided by the Honda class.
In this example, Shape is the abstract class, and its implementation is provided by the Rectangle
and Circle classes.
Mostly, we don't know about the implementation class (which is hidden to the end user), and an
object of the implementation class is provided by the factory method.
A factory method is a method that returns the instance of the class. We will learn about the factory
method later.
In this example, if you create the instance of Rectangle class, draw() method of Rectangle class
will be invoked.
File: [Link]
File: [Link]
class TestBank{
public static void main(String args[]){
Bank b;
b=new SBI();
[Link]("Rate of Interest is: "+[Link]()+" %");
b=new PNB();
[Link]("Rate of Interest is: "+[Link]()+" %");
}}
Test it Now
Rate of Interest is: 7 %
Rate of Interest is: 8 %
An abstract class can have a data member, abstract method, method body (non-abstract method),
constructor, and even main() method.
File: [Link]
Test it Now
bike is created
running safely..
gear changed
class Bike12{
abstract void run();
}
Test it Now
compile time error
Rule: If you are extending an abstract class that has an abstract method, you must either provide
the implementation of the method or make this class abstract.
The abstract class can also be used to provide some implementation of the interface. In such case,
the end user may not be forced to override all the methods of the interface.
Note: If you are beginner to java, learn interface first and skip this example.
1. interface A{
2. void a();
3. void b();
4. void c();
5. void d();
6. }
7.
8. abstract class B implements A{
9. public void c(){[Link]("I am c");}
10. }
11.
12. class M extends B{
13. public void a(){[Link]("I am a");}
14. public void b(){[Link]("I am b");}
15. public void d(){[Link]("I am d");}
16. }
17.
18. class Test5{
19. public static void main(String args[]){
20. A a=new M();
21. a.a();
22. a.b();
23. a.c();
24. a.d();
25. }}
Test it Now
Output:I am a
I am b
I am c
I am d
•
What is type inference?
Type inference refers to the automatic detection of the datatype of a variable, done generally at
Local variable type inference is a feature in Java 10 that allows the developer to skip the type
declaration associated with local variables (those defined inside method definitions, initialization
blocks, for-loops, and other blocks like if-else), and the type is inferred by the JDK. It will, then,
be the job of the compiler to figure out the datatype of the variable.
Till Java 9, to define a local variables of class type, the following was the only correct syntax:
For example:
import [Link];
import [Link];
class A {
Or
class A {
It looks fine, right? Yeah, because this is how things have been since the inception of Java. But
there is one issue: It’s pretty obvious that if the type of the object is clearly mentioned at the
right side of the expression, mentioning the same thing before the name of the variable makes
it redundant. Plus, in the second example, you can see that it’s obvious that after the ‘=’ sign,
it’s clearly a string as nothing except for a string can be enclosed in double inverted commas.
Therefore, there arose a need to eliminate this redundancy and make variable declaration
shorter, and more convenient.
How to declare local variables using LVTI:
Instead of mentioning the variable datatype on the left-side, before the variable, LVTI allows
you to simply put the keyword ‘var’. For example,
// variable declaration
import [Link];
import [Link];
class A {
import [Link];
import [Link];
class A {
Use Cases
Here are the cases where you can declare variables using LVTI:
1. In a static/instance initialization block
class A {
static
[Link](x)'
Output:
Oh hi there
2. As a local variable
class A {
[Link](x)
Output:
Hi there
3. As iteration variable in enhanced for-loop
class A {
arr = { 1, 2, 3 };
[Link](x + "\n");
Output:
1
2
3
4. As looping index in for-loop
class A {
arr = { 1, 2, 3 };
[Link](arr[x] + "\n");
Output:
1
2
3
5. As a return value from another method
class A {
int ret()
return 1;
[Link](x);
Output:
1
6. As a return value in a method
class A {
int ret()
var x = 1;
return x;
[Link](new A().ret());
Output:
1
Error cases:
There are cases where declaration of local variables using the keyword ‘var’ produces an error.
They’re mentioned below:
1. Not permitted in class fields
class A {
to be explicitly mentioned*/
class A {
class A {
on method parameters*/
// can't be 'var'
class A {
can't be var*/
return 1;
class A {
The Object class is the parent class of all the classes in java by default. In other words, it is the
topmost class of java.
The Object class is beneficial if you want to refer any object whose type you don't know. Notice
that parent class reference variable can refer the child class object, know as upcasting.
Let's take an example, there is getObject() method that returns an object but it can be of any type
like Employee,Student etc, we can use Object class reference to refer that object. For example:
1. Object obj=getObject();//we don't know what object will be returned from this method
The Object class provides some common behaviors to all the objects such as object can be
compared, object can be cloned, object can be notified etc.
Methods Description
The final keyword in java is used to restrict the user. The java final keyword can be used in many
context. Final can be:
1. variable
2. method
3. class
The final keyword can be applied with the variables, a final variable that have no value it is called
blank final variable or uninitialized final variable. It can be initialized in the constructor only. The
blank final variable can be static also which will be initialized in the static block only. We will
have detailed learning of these. Let's first learn the basics of final keyword.
class Bike9{
class Bike{
final void run(){[Link]("running...");}
}
class Honda2 extends Bike{
public static void main(String args[]){
new Honda2().run();
}
}
Output:running...
Q) What is blank or uninitialized final variable?
A final variable that is not initialized at the time of declaration is known as blank final variable.
If you want to create a variable that is initialized at the time of creating object and once initialized
may not be changed, it is useful. For example PAN CARD number of an employee.
class Bike10{
final int speedlimit;//blank final variable
Bike10(){
speedlimit=70;
[Link](speedlimit);
}
class Bike11{
int cube(final int n){
n=n+2;//can't be changed as n is final
n*n*n;
}
public static void main(String args[]){
Bike11 b=new Bike11();
[Link](5);
}
}
Output: Compile Time Error
Q) Can we declare a constructor final?
No, because constructor is never inherited.