0% found this document useful (0 votes)
211 views

Java Lex 2 3

The document discusses passing parameters to methods in Java. It explains that methods can accept data as arguments or parameters. It provides an example method that accepts total price and discount percentage as parameters and calculates the final price. It also discusses returning values from methods using the return statement. Local variables declared inside methods are explained as well as the different parameter passing techniques of pass by value and pass by reference. Constructors are introduced as special methods used to initialize objects. Parameterized and default constructors are demonstrated.

Uploaded by

Deepali Parse
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
211 views

Java Lex 2 3

The document discusses passing parameters to methods in Java. It explains that methods can accept data as arguments or parameters. It provides an example method that accepts total price and discount percentage as parameters and calculates the final price. It also discusses returning values from methods using the return statement. Local variables declared inside methods are explained as well as the different parameter passing techniques of pass by value and pass by reference. Constructors are introduced as special methods used to initialize objects. Parameterized and default constructors are demonstrated.

Uploaded by

Deepali Parse
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 106

PASSING PARAMETERS TO A METHODS

You will next see how to pass parameters or arguments to a method.

A method can accept data as arguments or parameters. Observe the


below payBill method which accepts totalPrice and discountPercentage as
parameters and calculates the final price to be paid.

EG: PUBLIC VOID PAYBILL(DOUBLE TOTALPRICE, DOUBLE DISCOUNTPERCENTAGE) {


SYSTEM.OUT.PRINTLN("CALCULATING FINAL AMOUNT TO BE PAID......");
DOUBLE PRICEAFTERDISCOUNT = TOTALPRICE * (1 - (DISCOUNTPERCENTAGE / 100));
SYSTEM.OUT.PRINTLN("HI " + CUSTOMERNAME
+ ", YOUR FINAL BILL AMOUNT AFTER DISCOUNT IS: "
+ (INT) (PRICEAFTERDISCOUNT * 100) / 100.0);
}

The values for the arguments need to be passed while calling the method is as
shown below in the code. The arguments passed while making the method call
are known as actual parameters and the arguments present in the method
header are known as formal parameters.

Eg: public static void main(String args[]) {


Customer customer = new Customer();
customer.customerId = "C101";
customer.customerName = "Stephen Abram";
customer.contactNumber = 7856341287L;
customer.address = "D089, St. Louis Street, Springfield, 62729";
customer.displayCustomerDetails();
customer.payBill(500, 10);
}

Observe the below output:


Returning values from a method

The result of a method can be given back by means of a return value by


using return statement as shown in the below method. A method can return only
one value at any point of time.

Eg: public double payBill(double totalPrice, double discountPercentage) {


System.out.println("Calculating final amount to be paid.....");
double priceAfterDiscount = totalPrice * (1 - (discountPercentage / 100));
return priceAfterDiscount;
}

The datatype of the return value must match the return type mentioned in
the method header. If the method does not return any value, void should be
mentioned as the return type in the method header.

LOCAL VARIABLES

You can also declare variables inside a method. These variables are known as local
variables and the scope of these variables is only within the method, i.e., they
cannot be accessed outside the method. Formal parameters are also local
variables.

Observe the below payBill method. The variable discountPercentage and the
parameter totalPrice are local variables.

EG: public double payBill(double totalPrice) {

double discountPercentage = 10;

System.out.println("Calculating final amount to be paid.....");

double priceAfterDiscount = totalPrice * (1 - (discountPercentage / 100));


return priceAfterDiscount;

PARAMETER PASSING TECHNIQUES

You will now understand the different parameter passing techniques.

1) PASS BY VALUE :

Whenever a value of a primitive data type is passed, the values are copied
from the actual parameters to the formal parameters. This kind of parameter
passing is known as pass by value. In pass by value, both the actual and formal
parameters point to different memory locations and the values are copied in both
the memory locations.

E.g.: public class Demo {

public void changeValue(int value1, int value2) {

value1 = value1 + value2;

value2 = value1 - value2;

System.out.println(value1 + " " + value2);

Observe the output when the method is called.

EG: public static void main(String args[]) {

Demo demo = new Demo();

int x = 20;

int y = 10;

System.out.println(x + " " + y);


demo.changeValue(x, y);

System.out.println("After calling changeValue function");

System.out.println(x + " " + y);

OUTPUT :

You can see that the values are changed only inside the method. This is because
any changes made inside the method will be reflected only in the memory
locations of the formal arguments and not in the memory locations of the actual
arguments.

2) PASS BY REFERENCE :

When an object is passed as a parameter, the formal and the actual parameters
both refer to the same object and hence the same memory location. Therefore,
the changes made inside the method to the formal parameters are reflected in the
actual parameters also. This kind of parameter passing is known as pass by
reference.

E.g.:

Observe the below updateContact method in Customer class which updates the
contact number of a customer.

public void updateContact(Customer customer) {

customer.contactNumber = 9786758497L;

Observe the output after the method is called.

EG: public static void main(String args[]) {

Customer customerOne = new Customer();


customerOne.contactNumber = 7656434567L;

System.out.println(customerOne.contactNumber);

customerOne.updateContact(customerOne);

System.out.println("After calling updateContact method");

System.out.println(customerOne.contactNumber);

OUTPUT:

CONSTRUCTORS

SENERIO:

By now, you have understood methods.

You will now understand how are objects created.

Whenever we create a new object, we need to assign values to the instance


variables individually for each object.

EG: public static void main(String args[]) {

Customer customer1 = new Customer();

customer1.customerId = "C101";

customer1.customerName = "Jack";

customer1.contactNumber = 9870345687L;

customer1.address = "Manor Farm Barns, Fox Road, Norwich, England";

Customer customer2 = new Customer();

customer2.customerId = "C102";

customer2.customerName = "Jane";
customer2.contactNumber = 7870098687L;

customer2.address = "Morningside Road, Edinburgh, Scotland";

Consider the scenario where we have many customers. We would have to initialize
each attribute of each object as shown above. This process would be much simpler
if we had some other way of initializing all the members of an object while creating
the object. This can be achieved by constructors.

CONSTRUCTOR:

A constructor in Java is a special method that is used to initialize class variables at


the time of object creation.

Each time an object is created using the new() keyword, a constructor is called. A
constructor can be created by the programmer. If the developer does not create
any constructor, then, Java provides a default constructor.

In the previous examples, we had not created any constructor, but Java provided
a default constructor for every class.

Constructors have the same name as that of the class and does not have a return
type.

Syntax:

<access modifier> <name> (<parameters>){

//body

Eg: public Customer(){

PARAMETERLESS CONSTRUCTOR

1) DEFAULT PARAMETERLESS CONSTRUCTOR :

A constructor with no arguments is known as a parameterless constructor. If you


don’t define a constructor in a class, then Java creates a default parameterless
constructor and initializes the default values to the class variables based on the
data type.

Eg: class Customer {

public String customerId;

public String customerName;

public long contactNumber;

public String address;

public class Tester {

public static void main(String args[]) {

Customer customer1 = new Customer();

System.out.println(customer1.customerId);

System.out.println(customer1.customerName);

System.out.println(customer1.contactNumber);

System.out.println(customer1.address);

Here, the default parameterless constructor is called every time a new object is
created and the default values to the member variables are assigned.

Observe the below output:

2) USER-DEFINED PARAMETERLESS CONSTRUCTOR :

You can also create parameterless constructor in a class. In this case, Java does
not create a separate default constructor.
EG: class Customer {

public String customerId;

public String customerName;

public long contactNumber;

public String address;

public Customer() {

System.out.println("Constructor called");

public class Tester {

public static void main(String args[]) {

Customer customer1 = new Customer();

System.out.println(customer1.customerId);

System.out.println(customer1.customerName);

System.out.println(customer1.contactNumber);

System.out.println(customer1.address);

Customer customer2 = new Customer();

Observe the below output:

PARAMETERIZED CONSTRUCTOR
Like any other method, a constructor can also accept parameters. Generally, these
are the values that need to be assigned to the instance variables of the class for
that object.

Eg:

class Customer {

public String customerId;

public String customerName;

public long contactNumber;

public String address;

Customer(String cId, String cName, long contact, String add) {

customerId = cId;

customerName = cName;

contactNumber = contact;

address = add;

The parameter values need to be passed while creating the object as shown
below.

Eg:

public class Tester {

public static void main(String args[]) {

Customer customer1 = new Customer("C103", "Jacob", 5648394590L,

"13th Street, New York");

System.out.println(customer1.customerId);
System.out.println(customer1.customerName);

System.out.println(customer1.contactNumber);

System.out.println(customer1.address);

Observe the Below Output :

MULITIPLE CONSTRUCTORS IN CLASS

A class can have multiple constructors to initialize different members. Based on


the arguments passed, the respective constructor is called.

EG:

class Customer {

public String customerId;

public String customerName;

public long contactNumber;

public String address;

public Customer() {

System.out.println("Parameterless constructor called");

public Customer(String cId, String cName, long contact, String add) {

System.out.println("Parameterized constructor called");

customerId = cId;
customerName = cName;

contactNumber = contact;

address = add;

public class Tester {

public static void main(String args[]) {

Customer customer1 = new Customer("C103", "Jacob", 5648394590L,

"13th Street, New York");

Customer customer2 = new Customer();

Observe the below output:

THIS KEYWORD

SCENARIO :

Consider the below constructor for Customer class.

Eg:

public Customer(String customerId, String customerName, long contactNumber,

String address) {

customerId = customerId;

customerName = customerName;
contactNumber = contactNumber;

address = address;

Here, the name of the instance variables of the class and the parameters passed
in the constructor are the same. In such a case, the local variables (arguments of
the constructor) have more priority and therefore, only the local variables will be
referred inside the above constructor. To overcome this problem, we
have this keyword which can be used to refer to the class members.

THIS KEYWORD :

this can also be used to invoke method or constructor of the current object.

Observe the code given below.

Eg:

public class Customer {

public String customerId;

public String customerName;

public long contactNumber;

public String address;

public Customer() {

System.out.println("Parameterless constructor called");

public Customer(String customerId, String customerName, long


contactNumber,

String address) {

// this() is used to invoke the constructor of the current class


// Since no parameters are specified, parameterless constructor will be
invoked

this();

this.customerId = customerId;

this.customerName = customerName;

this.contactNumber = contactNumber;

this.address = address;

public void displayCustomerName() {

System.out.println("Customer Name : " + customerName);

public void displayCustomerDetails() {

System.out.println("Displaying customer details \n***********");

System.out.println("Customer Id : " + customerId);

this.displayCustomerName();

System.out.println("Contact Number : " + contactNumber);

System.out.println("Address : " + address);

THIS KEYWORD TO INVOKE METHODS :

this can also be used to invoke method or constructor of the current object.

Observe the code given below.

Eg ;
public class Customer {

public String customerId;

public String customerName;

public long contactNumber;

public String address;

public Customer() {

System.out.println("Parameterless constructor called");

public Customer(String customerId, String customerName, long


contactNumber, String address) {

// this() is used to invoke the constructor of the current class

// Since no parameters are specified, parameterless constructor will be


invoked

this();

this.customerId = customerId;

this.customerName = customerName;

this.contactNumber = contactNumber;

this.address = address;

public void displayCustomerName() {

System.out.println("Customer Name : " + customerName);

public void displayCustomerDetails() {

System.out.println("Displaying customer details \n***********");


System.out.println("Customer Id : " + customerId);

this.displayCustomerName();

System.out.println("Contact Number : " + contactNumber);

System.out.println("Address : " + address);

MEMORY MANAGEMENT

MEMORY ALLOCATION – SCENARIO :

Till now you have learnt the basic concepts of OOP but have you wondered how
Java manages object creation in the memory?

Consider the Customer class.

Eg:

public class Customer {

public String customerId;

public String customerName;

public long contactNumber;

public String address;

public Customer(String customerId, String customerName, long


contactNumber, String address) {

this.customerId = customerId;

this.customerName = customerName;

this.contactNumber = contactNumber;

this.address = address;

}
// Methods of this class

What do you think will happen when the following statement gets executed?

Customer customerObj = new Customer("C101", "Stephen", 7856341287L,

"D089, Louis Street, Springfield, 62729");

MEMORY ALLOCATION :

A new Customer object referenced by customerObj will be created in the memory.

But how does it happen?

The memory is logically divided into two primary sections - Stack and Heap.

• All local variables and method invocations are stored in the stack
• All objects along with their instance variables are stored in the heap

Please note that reference variables are also local variables. Reference variables
are local variables which stores the address of another memory location.

You will now have a look at memory management in detail.

MEMORY ALLOCATION – STEPS :

Step 1: The reference variable is created in the stack.


Step 2: The object is created in the heap.

Step 3: The reference variable in the stack refers to the object in the heap.

Notes:

• One reference variable can point to one and only one object at a time.
• One object can be referenced by multiple reference variables at any given
point of time.

MEMORY DEALLOCATION :

Now that you have learnt how memory allocation happens, it is also important to
know the process of deallocating the memory.

Sometimes, even though a resource in a program is unreachable or not in use, the


memory used by that resource is not deallocated. This is called Memory leak and
is undesirable.

In some languages, it is the programmer's responsibility for deallocating the


memory occupied by such resources. Java, on the other hand, has a garbage
collector which automatically deallocates the memory used by such resources.
This prevents memory leak.
When an object does not have any reference, it becomes eligible for garbage
collection.

You might be wondering when does an object not have any reference and become
eligible for garbage collection?

Let us look at some of the possibilities.

GARBAGE COLLECTION - CASE 1 :

Case 1 - Objects eligible for garbage collection

• When the reference variable pointing to the object is initialized to null, the
object will not have any reference.

Eg:

public class Tester {

public static void main(String[] args) {

// Object creation

Customer customerObj = new Customer("C101", "Stephen Abram",

7856341287L, "D089, St. Louis Street, Springfield, 62729");

// Reference variable initialized to null

customerObj = null;

}
GARBAGE COLLECTION - CASE 2

Case 2 - Objects eligible for garbage collection

• When the reference variable is initialized to a new object and there is no


reference to the previous object

Eg: public class Tester {

public static void main(String[] args) {

// Object creation

Customer customerObj = new Customer("C101", "Stephen Abram",

7856341287L, "D089, St. Louis Street, Springfield, 62729");

// New object is set to the same reference

customerObj = new Customer("C102", "James", 7898766723L,

"D199, St. Louis Street, Springfield, 62729");

GARBAGE COLLECTION - CASE 3

Case 3 - Objects eligible for garbage collection


• When a reference variable is local to some method, it will be removed from
the stack as soon as the method finishes execution. The object pointed by
the reference variable then becomes eligible for garbage collection.

ENCAPSULATION

WHY DO WE NEED ENCAPSULATION?

You will now learn some more concepts and principles of object oriented
programming.

We all lock our phones and computers with strong password. This prevents
unauthorized access to our data present in the phone / computer. Unauthorized
access can lead to modifying, sharing and removing data. Similarly, we can restrict
certain parts of the code from directly accessing sensitive data.

ENCAPSULATION – SCENARIO :

Consider the code given below. Here, we are trying to access the attributes of
Customer class from another class. The data of the customer can be changed
directly by assigning new values to customerId, customerName, etc.

Eg:

class Customer {

public String customerId;

public String customerName;

public long contactNumber;


public String address;

public void displayCustomerDetails() {

System.out.println("Displaying customer details \n***********");

System.out.println("Customer Id : " + customerId);

System.out.println("Customer Name : " + customerName);

System.out.println("Contact Number : " + contactNumber);

System.out.println("Address : " + address);

System.out.println();

public class Tester {

public static void main(String args[]) {

Customer customer = new Customer();

customer.customerId = "C101";

customer.customerName = "Stephen Abram";

customer.contactNumber = 7856341287L;

customer.address = "D089, St. Louis Street, Springfield, 62729";

customer.displayCustomerDetails();

Output:
Ideally, the data should not be allowed to be changed directly by any external class
as the data can be changed without any validation.

ENCAPSULATION :

We can put a lock on the customer data so that it is not changed by any other class
by:

1. declaring the variables of a class as private


o Private variables are those which are accessible only inside the class
2. using public setter and getter methods within the class to set and get the
values of the fields
o The methods that are used to set values to private variables are
called setter methods.The methods that are used to fetch the values of
private variables are called getter methods.
o Getter methods are also known as accessor methods and setter
methods are also known as mutator methods.

This way of restricting access to data is called encapsulation.

Encapsulation is one of the basic principles of OOP.

Here, the variables of a particular class are hidden from other classes. We can
access these variables only through the methods of the class. Hence, it is also
referred as data hiding.

ABSTRACTION

You will now know one more basic principle of OOP, i.e., abstraction.
Abstraction is the process of exposing only relevant details. Let us consider the
example of withdrawing money from ATM. We insert the ATM card and follow
certain steps to withdraw money. We just ensure that we collect correct amount
of cash and correct amount gets deducted from the balance. We need not know
the internal working of the ATM to withdraw money. Here, the internal working of
the ATM is abstracted from the end-users.

Similarly, objects in OOP provide an abstraction that hides the internal


implementation details. You just need to know the methods that are available to
call and the input parameters required to call a method but you don’t need to
know how the method is implemented.

Given below is a small example about how abstraction is implemented in Java.


Here, we are invoking methods (withdraw() and balance() methods of Account
class) without knowing the logic of the methods.

EG:

public class Tester {

public static void main(String args[]) {

Account account = new Account("HDG37374"); // Passing the account


number

// Abstraction by invoking the methods of Bank class

account.withdraw(2000); // Passing the amount to be withdrawn

account.balance();

ACCESS MODIFIERS

So far, you have been using "public" and "private" keywords in your code. These
keywords are called access modifiers.

You will now understand them in more details.


They are used to specify access levels to control the visibility of a class and its
members. This facilitates encapsulation. There are 4 such access modifiers in Java:

• Public: Accessible from any other class


• Private: Accessible only inside its own class
• Protected: Accessible inside the same package and to the sub-classes in
different packages. This will be discussed in detail later in the course.
• Default: Accessible inside the same package. Members created without any
access modifier will have this access.

CLASS DIAGRAM

You have been learning about classes and objects and have been coding them but
it is also important to know how to diagrammatically represent the classes and
their structure. Classes and their structure can be diagrammatically represented
using class diagrams.

A class diagram is a diagram that is used to visualize the different aspects of a class.
It can be used to define the structure of the classes and the relationship among
them. Class diagram is the only UML (Unified Modeling Language) diagram which
can be directly mapped to object oriented languages and therefore, is one of the
most widely used UML diagrams.

In a class diagram, a class is represented by a rectangular box along with the


attributes and methods of the class.

Below is the class diagram of a class Customer which represents a customer of the
restaurant containing various attributes and methods.
The symbols denote the accessibility of the members:

• - denotes private members


• + denotes public members
• # denotes protected members

CLASS DIAGRAM IN ECLIPSE :

Class diagrams can be generated using IDEs also. Since in this course, we will be
working with Eclipse IDE, the class diagram generated in Eclipse is shown below:
Some of the symbols and their uses are given below:

STATIC

INTRODUCTION TO STATIC – SCENARIO :

Hope, you have understood the importance and utility of testing, debugging and
code analysis. Let us again get back and continue with some more concepts of
OOP.

Consider the below Customer class.

Eg :

class Customer {

private String customerId;

private String customerName;

private long contactNumber;

private String address;

public Customer(String customerId, String customerName, long


contactNumber,

String address) {

this.customerId = customerId;

this.customerName = customerName;

this.contactNumber = contactNumber;
this.address = address;

public String getCustomerId() {

return customerId;

public void setCustomerId(String customerId) {

this.customerId = customerId;

public String getCustomerName() {

return customerName;

public void setCustomerName(String customerName) {

this.customerName = customerName;

public long getContactNumber() {

return contactNumber;

public void setContactNumber(long contactNumber) {

this.contactNumber = contactNumber;

public String getAddress() {

return address;

}
public void setAddress(String address) {

this.address = address;

public void displayCustomerDetails() {

System.out.println("Displaying customer details \n***********");

System.out.println("Customer Id : " + customerId);

System.out.println("Customer Name : " + customerName);

System.out.println("Contact Number : " + contactNumber);

System.out.println("Address : " + address);

System.out.println();

public double payBill(double totalPrice) {

double discountPercentage = 5;

System.out.println("Calculating final amount to be paid.....");

double priceAfterDiscount = totalPrice * (1 - (discountPercentage /


100));

return priceAfterDiscount;

public class Tester {

public static void main(String[] args) {

Customer customer1 = new Customer("C1001", "Sam", 9945000009L,

"Carolina Street, Springfield, 62702");


System.out.println("Final amount to be paid: $"
+customer1.payBill(20));

The restaurant has now decided to charge $1.5 as a delivery charge from the
customers. In order to implement this requirement, we can create one more
attribute as deliveryCharge and set the value as $1.5.

Eg :

class Customer {

private String customerId;

private String customerName;

private long contactNumber;

private String address;

private float deliveryCharge;

public Customer(String customerId, String customerName, long


contactNumber,

String address, float deliveryCharge) {

this.customerId = customerId;

this.customerName = customerName;

this.contactNumber = contactNumber;

this.address = address;

this.deliveryCharge = deliveryCharge;

public String getCustomerId() {


return customerId;

public void setCustomerId(String customerId) {

this.customerId = customerId;

public String getCustomerName() {

return customerName;

public void setCustomerName(String customerName) {

this.customerName = customerName;

public long getContactNumber() {

return contactNumber;

public void setContactNumber(long contactNumber) {

this.contactNumber = contactNumber;

public String getAddress() {

return address;

public void setAddress(String address) {

this.address = address;

}
public void displayCustomerDetails() {

System.out.println("Displaying customer details \n***********");

System.out.println("Customer Id : " + customerId);

System.out.println("Customer Name : " + customerName);

System.out.println("Contact Number : " + contactNumber);

System.out.println("Address : " + address);

System.out.println();

public double payBill(double totalPrice) {

double discountPercentage = 5;

System.out.println("Calculating final amount to be paid.....");

double priceAfterDiscount = totalPrice * (1 - (discountPercentage /


100));

double finalBillAmount=priceAfterDiscount + deliveryCharge;

return finalBillAmount;

public class Tester {

public static void main(String[] args) {

Customer customer1 = new Customer("C1001", "Sam", 9945000009L,

"Carolina Street, Springfield, 62702", 1.5f);

System.out.println("Final amount to be paid: $"


+customer1.payBill(20));

}
}

In the previous implementation, we have created one attribute deliveryCharge.


Since the delivery charge will be the same for all customers, we can directly set the
value inside the constructor instead of passing the value as parameter to the
constructor as shown below.

Eg :

public Customer(String customerId, String customerName, long contactNumber,

String address) {

this.customerId = customerId;

this.customerName = customerName;

this.contactNumber = contactNumber;

this.address = address;

this.deliveryCharge = 1.5f;

WHY DO WE NEED STATIC ?

Though the delivery charge is same for all the customer objects, but in this case,
the value of delivery charge is maintained for each and every customer object.

So, instead of storing the delivery charge separately for each and every customer
object, it would have been better if we could have maintained a single copy of the
delivery charge which could be accessible by all the customer objects.

Usually, values of member variables can be accessed only by that object. But here,
we need a variable whose value could be shared by all the objects of a class, i.e.,
the entire class.

In, object oriented programming languages like Java, there is a concept of creating
a static variable.

A static variable belongs to an entire class and not to a specific object.

STATIC VARIABLE
When a variable is declared as Static, then a single copy of the variable is created
and shared among all objects at the class level. Memory allocation for such
variables happen only once when the class is loaded in the memory. These
variables are also known as class-level variables.

Since static variables and instance variables are both members of the class, they
are often referred to as member variables.

DECLARATION OF STATIC VARIABLE :

To create a static member variable, precede its declaration with the


keyword static. When a member is declared static, it can be accessed before any
object of the class is created and without reference to any object.

Syntax:

private static float deliveryCharge ; //Declaration of static variable

Since the static variable gets created only once, now only one deliveryCharge
member variable will be created and all the objects of that class will share that
member variable. This can be visualized as
INITIALIZATION OF STATIC VARIABLE :

How can we initialize the static variables?

One way to initialize the static variable is to initialize at the time of declaration as
shown below

private static float deliveryCharge = 1.5f;

This is fine if you have to directly initialize a value but this would not work if you
need to perform some computation and then initialize the value of a static
member variable.

In that case, Java provides one more type of static member called static block.

STATIC BLOCK

Static blocks are used to initialize static variables when it cannot be done in a single
line. They can also be used to add preprocessing if required.

In the scenario of the delivery charge, the static variable deliveryCharge can be
initialized with the help of static block as shown below

static {

deliveryCharge = 1.5f; // initialize the static variable

This can be visualized as


STATIC BLOCK – SCENARIO :

Static blocks get executed only once when a class gets loaded in memory. If there
are multiple static blocks, they will be executed in the order of their occurrence.

After implementing static variable and static block, the Customer class looks as
shown below.

EG:

class Customer {

private String customerId;

private String customerName;

private long contactNumber;

private String address;


private static float deliveryCharge;

static {

deliveryCharge = 1.5f;

public Customer(String customerId, String customerName, long


contactNumber,

String address) {

this.customerId = customerId;

this.customerName = customerName;

this.contactNumber = contactNumber;

this.address = address;

public String getCustomerId() {

return customerId;

public void setCustomerId(String customerId) {

this.customerId = customerId;

public String getCustomerName() {

return customerName;

public void setCustomerName(String customerName) {

this.customerName = customerName;
}

public long getContactNumber() {

return contactNumber;

public void setContactNumber(long contactNumber) {

this.contactNumber = contactNumber;

public String getAddress() {

return address;

public void setAddress(String address) {

this.address = address;

public void displayCustomerDetails() {

System.out.println("Displaying customer details \n***********");

System.out.println("Customer Id : " + customerId);

System.out.println("Customer Name : " + customerName);

System.out.println("Contact Number : " + contactNumber);

System.out.println("Address : " + address);

System.out.println();

public double payBill(double totalPrice) {

double discountPercentage = 5;
System.out.println("Calculating final amount to be paid.....");

double priceAfterDiscount = totalPrice * (1 - (discountPercentage /


100));

double finalBillAmount=priceAfterDiscount + deliveryCharge;

return finalBillAmount;

STATIC METHOD

STATIC METHODS – SCENARIO :

How can you access the static variable deliveryCharge in order to display the total
bill amount which has to be paid by the customers?

One way of accessing the static variable is with the help of instances of the class as
shown below

Eg :

// Accessing the static variable with the help of instance of the class

System.out.println("Delivery Charge for customer1 is "+


customer1.deliveryCharge);

Since the static variables are not specific to an object, accessing a static variable
using an object is not the correct way.

Instead, static variables should be accessed with the help of class name instead of
the instance of the class as shown below:

Eg :

// Accessing the static variable with the help of class

System.out.println("Delivery Charge for customer1 is "+


Customer.deliveryCharge);

STATIC METHODS :
Next you will see, how can you update or retrieve the value of a static variable?

To update or retrieve the value of a static variable, you need to use the setter and
getter methods.

Since static variable is not specific to an object, you need a way to access the setter
and getter methods without an object. This is possible by creating static methods.

HOW TO USE STATIC METHODS ?

Static methods are methods prefixed with the static keyword. These methods can
be accessed without an object of the class. Similar to static variables, they are
accessed using the class name. A static method can be invoked without creating
an instance of a class.

A static method can only access static variables and cannot access instance
variables.

In case of the delivery charge scenario, you can create static setter and getter
methods for deliveryCharge as shown below

Eg :

public static float getDeliveryCharge() {

return deliveryCharge;

public static void setDeliveryCharge(float deliveryCharge) {

Customer.deliveryCharge = deliveryCharge;

ACCESSING OTHER MEMBERS FROM STATIC METHODS :

What happens if you try to access the deliveryCharge in setDeliveryCharge()


method with the help of this?

Eg:

public static void setDeliveryCharge(float deliveryCharge) {


// Which object's deliveryCharge?

this.deliveryCharge = deliveryCharge; // This line will throw error

Static blocks and static methods cannot access non-static (instance) members
directly since static methods do not belong to any object, so it is not possible to
know which object's instance variables should be accessed. Trying to do so will
result in a compilation error.

However, non-static methods can access static members.

IMPLEMENTATION OF STATIC

The following code shows the implementation of Customer class with static
variables, static blocks and static methods.

EG:

class Customer {

private String customerId;

private String customerName;

private long contactNumber;

private String address;

private static float deliveryCharge;

static {

deliveryCharge = 1.5f;

public Customer(String customerId, String customerName, long contactNumber,


String address) {

this.customerId = customerId;

this.customerName = customerName;
this.contactNumber = contactNumber;

this.address = address;

public String getCustomerId() {

return customerId;

public void setCustomerId(String customerId) {

this.customerId = customerId;

public String getCustomerName() {

return customerName;

public void setCustomerName(String customerName) {

this.customerName = customerName;

public long getContactNumber() {

return contactNumber;

public void setContactNumber(long contactNumber) {

this.contactNumber = contactNumber;

public String getAddress() {

return address;
}

public void setAddress(String address) {

this.address = address;

public static float getDeliveryCharge() {

return deliveryCharge;

public static void setDeliveryCharge(float deliveryCharge) {

Customer.deliveryCharge = deliveryCharge;

public void displayCustomerDetails() {

System.out.println("Displaying customer details");

System.out.println("Customer Id: " + this.customerId);

System.out.println("Customer Name: " + this.customerName);

System.out.println("Contact Number: " + this.contactNumber);

System.out.println("Address: " + this.address);

System.out.println("Delivery Charge: " + Customer.deliveryCharge);

System.out.println();

public double payBill(double totalPrice) {

double discountPercentage = 5 System.out.println("Calculating final amount to be


paid.....");

priceAfterDiscount = totalPrice * (1 - (discountPercentage / 100));


double finalBillAmount = priceAfterDiscount + Customer.deliveryCharge;

return finalBillAmount;

public class Tester {

public static void main(String[] args) {

Customer customer1 = new Customer("C1001", "Sam", 9945000009L, "Carolina


Street, Springfield, 62702");

Customer.setDeliveryCharge(2f);

System.out.println("Final amount to be paid: $" + customer1.payBill(20));

Customer customer2 = new Customer("C1002", "John", 9645000009L, "Carolina


Street, Springfield, 6270

System.out.println("Final amount to be paid: $" + customer2.payBill(15));

System.out.println("Delivery Charge for the customers are: " +


Customer.getDeliveryCharge());

AUTO GENERATION OF IDS :

Another most common implementation of the static concept is in auto-generation


of Ids.

Let us assume that we want to generate the customer Ids for all the customers. All
the customer Ids must be unique and it should start with 'C101'. In order to
implement this requirement and generate the customerId for all the customers,
the concept of static is used as shown below.

EG:

class Customer {
private static int counter; // Declaring the static variable counter

private String customerId;

private String customerName;

private long contactNumber;

private String address;

private static float deliveryCharge;

static {

deliveryCharge = 1.5f;

counter = 100; // Initializing the static variable counter

public Customer(String customerName, long contactNumber, String address) {

// Incrementing the counter and initializing customerId

this.customerId = "C" + ++Customer.counter;

this.customerName = customerName;

this.contactNumber = contactNumber;

this.address = address;

// Static method to get the value of static variable counter

public static int getCounter() {

return counter;

// Static method to change the value of static variable counter if needed

public static void setCounter(int counter) {


Customer.counter = counter;

public String getCustomerId() {

return customerId;

public void setCustomerId(String customerId) {

this.customerId = customerId;

public String getCustomerName() {

return customerName;

public void setCustomerName(String customerName) {

this.customerName = customerName;

public long getContactNumber() {

return contactNumber;

public void setContactNumber(long contactNumber) {

this.contactNumber = contactNumber;

public String getAddress() {

return address;

}
public void setAddress(String address) {

this.address = address;

public static float getDeliveryCharge() {

return deliveryCharge;

public static void setDeliveryCharge(float deliveryCharge) {

Customer.deliveryCharge = deliveryCharge;

public void displayCustomerDetails() {

System.out.println("Displaying customer details");

System.out.println("Customer Id: " + this.customerId);

System.out.println("Customer Name: " + this.customerName);

System.out.println("Contact Number: " + this.contactNumber);

System.out.println("Address: " + this.address);

System.out.println("Delivery Charge: " + Customer.deliveryCharge);

System.out.println();

public double payBill(double totalPrice) {

double discountPercentage = 5;

System.out.println("Calculating final amount to be paid.....");

double priceAfterDiscount = totalPrice * (1 - (discountPercentage / 100));

double finalBillAmount = priceAfterDiscount + Customer.deliveryCharge;


return finalBillAmount;

public class Tester {

public static void main(String[] args) {

Customer customer1 = new Customer("Sam", 9945000009L, "Carolina Street,


Springfield, 62702");

Customer customer2 = new Customer("John", 9645000009L, "Carolina Street,


Springfield, 62708");

Customer customer3 = new Customer("Alex", 9745000009L, "Carolina Street,


Springfield, 62768");

System.out.println("Customer Id for the first customer is: " +


customer1.getCustomerId());

System.out.println("Customer Id for the second customer is: " +


customer2.getCustomerId());

System.out.println("Customer Id for the third customer is: " +


customer3.getCustomerId());

AGGREGATION

INTRODUCTION TO RELATIONSHIPS :

So far, we have been dealing with classes and objects which don’t interact with
other classes, but in real life, objects interact with objects of other classes. Let
us look at an example:
Here, Student and Hostel both are separate classes having their own existence.
They both are related to each other as a Student 'lives in' a Hostel.

Below are some other examples that show how different classes may be related to
each other:

• Employee drinks Coffee


• Customer buys a Phone
• College has a Department
• Car has a Wheel

In OOP, two classes can communicate with each other using their objects. An
object may communicate with another object to use the functionalities provided
by the other object. This is very helpful if we want to reuse the members of a class
in another. Some of the types of relationships in Java are:

AGGREGATION :

The first relationship that you will see is Aggregation which is also known as Has-
a relationship. This kind of relationship exists between two classes when a
reference variable of one class is a member variable in another class. Consider the
below examples.

Example 1: - Consider a class Department. Department will have various member


variables like department name, department Id. Apart from these member
variables, a department also has a manager. This manager is actually an Employee
and will have different set of member variables. The member variable manager in
the Department class will be a reference of Employee class. In this case, we can
say, Department has a manager (Employee) which is an Aggregation relationship.
Example 2: - Consider a Library class. A library has many books. Each book will have
its own set of characteristics and hence, Book will be a separate class. In the Library
class, book will be a member variable and will be of the type Book class. In this case
also, we can say, Library has books which is also an Aggregation relationship.

IMPLEMENTATION OF AGGREGATION :

Let us now consider the SwiftFood app. Consider the Order and Food class

Eg:

public class Order {

private int orderId;

private Food orderedFoods;

private double totalPrice;

private String status;

public Order(int orderId, Food orderedFoods) {

this.orderId = orderId;

this.orderedFoods = orderedFoods;

this.status = "Ordered";

}
}

Eg :

public class Food {

private String foodName;

private String cuisine;

private String foodType;

private int quantityAvailable;

private double unitPrice;

You can see that the class Order has a member variable 'orderedFood' of type Food
which indicates the food that is being ordered. Here, we can say that Order has-
a Food which is an Aggregation relationship.

The modified class diagram is shown below.

Note: In class diagram, aggregation is represented by a link with a diamond head.

The Food object and the Order object both will exist independently and you need
to pass the Food object while creating the Order object as shown below.

Eg :

public static void main(String[] args) {

Food food = new Food();


food.setFoodName("Pizza Margherita");

food.setCuisine("Italian");

food.setFoodType("Veg");

food.setQuantityAvailable(10);

food.setUnitPrice(8.0);

Order order = new Order(101, food);

System.out.println("Order placed successfully!");

System.out.println("You have ordered: "+


order.getOrderedFoods().getFoodName());

System.out.println("Order status: "+ order.getStatus());

The output is shown below:

Here, you can observe that the variable orderedFood acts like any other member
variable and can be directly accessed using the Order object. In order to access the
members of the Food class using the reference variable of Order class, we can
make use of dot '.' just like any other reference variable shown above.

IMPLEMENTATION OF AGGREGATION :

Eg:

public class Order {

private int orderId;


private Food[] orderedFoods;

private double totalPrice;

private String status;

public Order() {

this.status = "Ordered";

public Order(int orderId, Food[] orderedFoods)

this.orderId = orderId;

this.orderedFoods = orderedFoods;

this.status = "Ordered";

public static int getTotalNoOfOrders() {

return Order.orderIdCounter-100;

public Food[] getOrderedFoods() {

return orderedFoods;

public void setOrderedFoods(Food[] orderedFoods) {

this.orderedFoods = orderedFoods;

}
//other methods

public double calculateTotalPrice(String paymentMode) {

double foodPrice = 0;

double finalPrice = 0;

float serviceCharge = 0f;

for (Food food : orderedFoods) {

foodPrice+=food.getUnitPrice()*1;

if (paymentMode.equals("Credit Card") || paymentMode.equals("Debit Card")) {

serviceCharge = 2.0f;

else if (paymentMode.equals("PayPal")) {

serviceCharge = 2.9f;

finalPrice = foodPrice+foodPrice*(serviceCharge/100);

this.setTotalPrice(finalPrice);

return finalPrice;

Also, observe the modified calculateTotalPrice method which now accepts the
paymentMode as the parameter and according to the payment mode, applies
service charge to the final price of the order.
ASSOCIATION

Association, also known as uses-a relationship exists between two classes when
one object makes use of another object for its functionality. Here, both the objects
can exist independently.

Example 1: - Consider a class Patient. A patient needs to take an appointment to


visit the hospital. Appointment and Patient are separate classes. Also, an
appointment cannot be categorized as one of the attributes of the patient. Rather
this appointment is only used by the patient and is said to have Association
relationship.

Example 2: - Consider a class Driver and a class Car. We can say that a driver uses
a car to travel.

ASSOCIATION – SCENARIO :

Let us consider the billing scenario of the SwiftFood app. Consider the
method generateBill of class Bill. This method is used to generate bill for
a particular order. Here, a reference of an Order object is passed to the method as
shown in the class diagram below.
Note: In class diagram, Association is represented by an arrow as shown below.
When you generate the class diagram in Eclipse, it is represented by a straight line
as shown above.

The generateBill method makes use of the Order object to display the order details
as shown below. This kind of uses a relationship is known as Association.

Eg:

public boolean generateBill(Order order) {

System.out.println("Bill details \n***********");

System.out.println("Bill Id : " + this.getBillId());

System.out.println("Items ordered : ");

for (Food food : order.getOrderedFoods()) {

System.out.println(food.getFoodName());

double payableAmount = order.calculateTotalPrice(this.getPaymentMode());

System.out.println("Payable Amount : $" + (int) (payableAmount * 100)/ 100.0);

return true;

You can test the method by writing the below code in main:

Eg :
public static void main(String[] args) {

Food food1 = new Food();

food1.setFoodName("Hamburger");

food1.setFoodType("Non-Veg");

food1.setCuisine("American");

food1.setUnitPrice(3.8);

food1.setQuantityAvailable(20);

Food food2 = new Food();

food2.setFoodName("Baked Apple Pie");

food2.setFoodType("Veg");

food2.setCuisine("American");

food2.setUnitPrice(20);

food2.setQuantityAvailable(25);

Food orderedFoods[]= new Food[] {food1,food2};

Order order = new Order(101, orderedFoods);

Bill bill = new Bill("PayPal")bill.generateBill(order);

The output is shown below:


INHERITANCE

You will now have a look at one more relationship type.

Let us consider the scenario of SwiftFood app. The customers of SwiftFood can be
divided into three types: Regular, Premium and Guest. Regular and Premium
customers are eligible for 5% and 8% discounts respectively on their orders. Also,
premium customers are provided with premium cards so that they can redeem
points while ordering food. Guests pay delivery charges for their orders.

Though Regular customers, Premium customers and Guests have different billing
mechanism, they have some common attributes like customerId, customerName,
contactNumber and address.

So, instead of keeping the common attributes in each and every class, we can have
a common class called Customer and include the common attributes.

IS A RELATIONSHIP

Now, let us consider RegularCustomer and Guest classes. Since RegularCustomer


and Guest are types of Customers, they must have access to the common
attributes also. We can create a Customer class with the common attributes and
methods and make these two classes inherit the attributes and behavior from
Customer class as shown below.
The common members that are inherited are represented using blue color. The
members specific to RegularCustomer and Guest are represented using green
color.

We can say that the RegularCustomer "is-A" Customer and Guest "is-A"
Customer. When a class inherits from another class, then those classes are said to
have inheritance relationship. The class which is inheriting is called
the child/sub/derived class and the class which is getting inherited is called
the parent/super/base class. Inheritance is also called as "is-A"
relationship. Inheritance (is-a) is denoted by a line with an arrow head.

In our example, RegularCustomer and Guest classes are inheriting the


Customer class. So, Customer is the parent class and RegularCustomer and Guest
are child classes.

WHAT GETS INHERITED?

n case of an inheritance relationship, the attributes and behaviors get inherited


just like a child inherits certain attributes and behaviors from his/her parent.

In terms of OOP, a child class inherits all the non-private attributes and methods.

When we say a child class inherits the attributes and methods, we can treat the
attributes and methods as if they are owned by the child class itself.

EXTENDS KEYWORD :

In Java, a child class inherits the parent class using the "extends" keyword. Observe
the below code.

EG:
class Customer {

//Parent/Super/Base class

class RegularCustomer extends Customer { // RegularCustomer is a Customer

//Child/Sub/Derived class

class Guest extends Customer { // Guest is a Customer

//Child/Sub/Derived class

Let us take one more example. In an organization, we have employees of different


designations. Let us consider Project Manager and System Engineer. All the
employees have common attributes like Id, name and email id. So, we can have a
common class called Employee and include these attributes. The Project Manager
and System Engineer classes can inherit the Employee class.

EG:

class Employee {

// Parent/Super/Base class

class ProjectManager extends Employee { // ProjectManager is an Employee

// Child/Sub/Derived class

class SystemEngineer extends Employee { // SystemEngineer is an Employee

// Child/Sub/Derived class

}
CONSTRUCTOR CALL IN INHERITANCE

By now, you have learnt that the derived classes inherit from the base class. You
will now see how the child class object is created. As you all know, constructors
are invoked while creating objects. When a child class object is created, the child
class constructor invokes the parent class constructor before executing any
statement present in the child constructor.

Observe the below code and understand the sequence of constructor invocation.

EG:

class Customer {

public Customer() {

// 3: Parent constructor will be executed

System.out.println("Creating a customer...");

// 4: The flow will go back to the child constructor

class RegularCustomer extends Customer {

public RegularCustomer() {

// 2: This constructor will then call the parent constructor

System.out.println("It is a regular customer!");

// 5: The flow will finally come here

public class Tester {

public static void main(String[] args) {


RegularCustomer regularCustomer = new RegularCustomer();

// 1: This line will be executed first and the flow will go to [2]

NEED OF SUPER CONSTRUCTORS

NEED FOR SUPER CONSTRUCTORS – SCENARIO :

Let us consider the scenario of SwiftFood. We have a Customer class which


consists of private member variables customerId, customerName, setter and
getter methods to set and access the private member variables and
displayCustomerDetails() method to display the customer details.

Eg:

class Customer {

private String customerId;

private String customerName;

public Customer(String customerId, String customerName) {

this.customerId = customerId;

this.customerName = customerName;

public Customer() {

System.out.println("Parent Default Constructor");

public String getCustomerId() {

return customerId;

}
public void setCustomerId(String customerId) {

this.customerId = customerId;

public String getCustomerName() {

return customerName;

public void setCustomerName(String customerName) {

this.customerName = customerName;

public void displayCustomerDetails() {

System.out.println("Displaying customer details


\n***************************");

System.out.println("Customer Id : " + customerId);

System.out.println("Customer Name : " + customerName);

System.out.println();

The RegularCustomer class extends Customer class. Only the Regular customers
are provided with a discount of 5% on the total cost, so we have the discount
attribute in the RegularCustomer class. The common attributes like customerId,
customerName, contactNumber and address are not included here. Those
attributes will be inherited from the parent class. Observe how the values are being
set for all the variables.

Eg:

class RegularCustomer extends Customer {


private float discount;

public RegularCustomer(String custId, String custName) {

this.setCustomerId(custId);

this.setCustomerName(custName);

this.discount = 5.0f;

System.out.println("Child Constructor");

public float getDiscount() {

return discount;

public void setDiscount(float discount) {

this.discount = discount;

In the Tester class, we are creating the child (RegularCustomer) class object. First,
the control will go to RegularCustomer constructor. The flow will then move to
parent (Customer) class constructor. After execution of the parent class
constructor, the child class constructor will get executed.

Eg:

public class Tester {

public static void main(String[] args) {

RegularCustomer regularCustomer = new RegularCustomer("C1010” "Johns


Kora");

regularCustomer.displayCustomerDetails();
}

Output :

INVOKING PARAMETERIZED CONSTRUCTOR

In the previous code snippet, the member variables were being set in the child
class constructor and the parameterized constructor of parent class.

Instead of setting the values of member variables in both the places, it would be
better if the parameterized constructor of parent class is invoked from the child
class constructor so that code can be reused.

By now, you know that the parent class parameterless constructor is implicitly
invoked by the child class constructors but how are parameterized constructors of
parent class invoked?

This can be done using super as shown in the code given below.
Eg:

class Customer {
private String
customerId; private String
customerName;
public Customer(String customerId, String customerName) {
this.customerId = customerId;
this.customerName = customerName;
}
public void displayCustomerDetails() {
System.out.println("Displaying customer details
\n***************************");
System.out.println("Customer Id : " + this.customerId);
System.out.println("Customer Name : " + this.customerName);
}
}
class RegularCustomer extends Customer {
private float discount;
public RegularCustomer(String custId, String custName) {
super(custId, custName); // Invoking the parent class parameterized
constructor this.discount = 5.0f;
}
public float getDiscount()
{ return discount;
}
public void setDiscount(float discount) {
this.discount = discount;
}
}
public class Tester {
public static void main(String[] args) {
RegularCustomer regularCustomer = new RegularCustomer("C1010",
"Johns Kora"); regularCustomer.displayCustomerDetails();
}
}

Please also note that the call to a super constructor has to be the first statement
inside a constructor.

In fact, the parameterless constructor of the parent class gets implicitly called by

the child class constructors due to an implicit super() statement. This can also be

done explicitly as shown below. Eg: class RegularCustomer extends Customer {

public RegularCustomer() { super(); // Invoking the parent class constructor

System.out.println("It is a regular customer!");

}
}

TYPES OF INHERITANCE

1) Single Inheritance :

There are multiple types of inheritance. We will be discussing some of them in this
course.

The first type of inheritance that we will be discussing is Single Inheritance.

In single inheritance, one class is extended by only one class.

You can see in the image given below that only one class, i.e., RegularCustomer
extends There are multiple types of inheritance. We will be discussing some of
them in this course.

Eg: public class Customer {

// Parent/Super/Base class

public class RegularCustomer extends Customer { // RegularCustomer is a


Customer

// Child/Sub/Derived class

}
2) Multilevel Inheritance :

The next type of inheritance that we will be discussing is Multilevel inheritance.

In multilevel inheritance, a class extends another class which extends another


class. SwiftFood app has one more category of customers - PremiumCustomers.
PremiumCustomers are special type of RegularCustomers who are provided with
reward points apart from getting discount.In this case, the RegularCustomer class
extends the Customer class and the PremiumCustomer class extends
the RegularCustomer class. This is an example of Multilevel inheritance.

Eg: public class Customer {

//code

public class RegularCustomer extends Customer {

//code

public class PremiumCustomer extends RegularCustomer {

//code

}
3) Hierarchical Inheritance :

One more type of Inheritance is Hierarchical Inheritance.

When more than one class extends the same base class, then that type of
inheritance is said to be Hierarchical Inheritance.Here, the Customer class is the
parent class and the RegularCustomer and Guest classes extend the Customer
class. This is an example of Hierarchical Inheritance.

Eg: public class Customer {

// code here

public class RegularCustomer extends Customer {

// code here

public class Guest extends Customer {

// code here

4) Multiple Inheritance :

The last type of Inheritance that we will discuss is Multiple Inheritance.In Multiple
Inheritance, one class extends multiple classes.In the below example, Manager is
an Employee as well as an Educator. So, Manager class extends both Employee
and Educator class.
Please note that Multiple Inheritance is NOT supported in many object oriented
programming languages including Java.

POLYMORPHISM

Introduction to polymorphism :

Polymorphism is the ability of an object to take different forms, i.e., a single action
that can be performed in different ways. So, polymorphism means many forms.

Consider a simple example of a Bank. All the banks are providing loans to its
customers.

But are they all providing it at the same rate?

No, rate of interest may differ from bank to bank. So, object of the Bank class may
behave differently when we try to get the interest rate for bank loans (through a
method).

The Bank class, here, shows polymorphism.

Eg:

Consider the SwiftFood scenario in which a Customer is ordering food online.

Based on the different types of customers, the final price and thus the payment of
bill gets changed. This is because, the Guests are charged a delivery charge of $2.0
and other registered customers get some discounts. Among them, Regular
Customer gets a discount of 5% and Premium Customers 8%. Premium Customers
also have a provision to pay the bill using their membership card points.

So, the final payment of the bill differs for each of the customers. Thus, Customer
class also exhibits polymorphism.

Polymorphishm is of two types:


• Static polymorphism
• Dynamic polymorphism

STATIC POLYMORPHISM

Polymorphism that gets resolved during compile time is known as static


polymorphism or compile time polymorphism. This polymorphism is achieved
using overloading of the methods in the same class, called as Method
overloading.

Method overloading allows the programmer to have multiple methods with the
same name in the same class, but differing in their signature.

Signature can differ by

• the number of parameters


• the data type of parameters
• the order of the parameters

Note: We cannot overload methods by their return type, i.e., two or more methods
are not overloaded if they differ only in their return type.

Consider the scenario where the customer of SwiftFood app needs to update his

or her contact number. For this requirement, we will have a method

updateContact(long mobile) as follows: Eg: public class Customer { private String

customerId; private String customerName; private long contactNumber; private

Address address; public void updateContact(long mobile) {

System.out.println("Updating customer contact number...");

this.setContactNumber(mobile);

// Constructors and other methods


}

So, here different methods are getting added to the code which are basically doing
the same thing of updating the customer details which can be either contact
number or address or any other details.

Thus, is there any need of having these methods with a different name?

No, since we have the option of creating overloaded methods, i.e., methods with
same name differing in signature, we can use overloaded methods in this scenario.

Here, the advantage is that we don’t have to create and remember different
names for methods doing same functionality. For example, if overloading was not
supported, we would have to create different method names like updateContact,
updateAddress, updateContactAddress etc.

Considering this, our code will be modified as shown below:


Eg: public class Customer {

private String customerId;

private String customerName;

private long contactNumber;

private Address address;

public void updateDetails(long

mobile) {

System.out.println("Updating customer contact number...");

this.setContactNumber(mobile);

}
public void updateDetails(Address address) {

System.out.println("Updating customer address...");

this.setAddress(address);

// Constructors and other methods

}
Here, the Customer class is having two methods (having same behavior of
updating the customer details) with same name: updateDetails() but both the
methods differ in the data type of the parameter. This is Method
Overloading and both the updateDetails methods are said to
be overloaded methods.
Overloaded methods are invoked just the usual way, where the method which
matches the signature is invoked.
Eg: public class Tester {
public static void main(String[] args) {
Customer customer = new Customer("C1016", "Stephen Abram", 7856341287L,
custAddress);

Long newContact = 7890098656L;

Address newAddress = new Address("D119", "St. Louis Street", "Springfield",


62729);

customer.updateDetails(newCo
ntact);//callsthe
updateDetails(long mobile) -
based on the
parame
ter

customer.updateDetails(newAddress);
//calls the updateDetails(Address
address) - based on the parameter

Calls to the overloaded methods can be resolved based on the method signature
during compilation and thus the name compile-time or static polymorphism.

Constructor overloading :

Eg: class Customer {

private String

customerId; private String

customerName; private

long contactNumber;

private Address address;

// Parameterless

constructor public

Customer() {

System.out.println("Inside parameterless constructor");

// Parameterized constructor

public Customer(String customerId, String customerName, long

contactNumber,

Address address) {
this.customerId = customerId;

this.customerName = customerName;

this.contactNumber = contactNumber;

this.address = address;

// Parameterized constructor

public Customer(String customerName, long contactNumber, Address

address) {

this.customerName =

customerName;

this.contactNumber = contactNumber;

this.address = address;

// Methods including getter and setter and other methods

public class Tester {

public static void main(String[] args) throws

Exception {

/*
Parameterless constructor will be invoked, instance

variables should be initialized using setter methods

*/

Customer customerOne = new Customer();

/*

Parameterized constructor with four parameters instance variables are

initialized in the constructor

*/

Customer customerTwo = new Customer("C1016", "Stephen Abram",

7856341287L, new Address("D089", "St. Louis Street "Springfield", 62729));

/*

Parameterized constructor with three parameters instance

variables are initialized in the constructor

*/

Customer customerThree = new Customer("James Jonathan",

7828171287L, new Address("D159", "St. Louis Street",

"Springfield", 62729));

DYNAMIC POLYMORPHISM
Similar to static polymorphism or compile time polymorphism, polymorphism can
also be achieved at runtime. Such type of polymorphism is known as dynamic
polymorphism. This type of polymorphism is achieved using overriding the parent
method in the child class, called as Method Overriding.

Overriding feature allows the programmer to have a different implementation of


parent methods with the same signature in the child classes. Such parent methods
are said to be overridden.

• When we override a method in the child class, it should have the same
signature as that of the parent class.
• The method should not have a weaker access modifier.
• Private methods are not overridden.

EXAMPLE OF DYNAMIC POLYMORPHISM :

Consider the parent Customer class.

All the customers’ need to pay the bill amount calculated for their orders. There is
a payBill() in the Customer class for calculating the final amount for bill payment.

You need to also remember that calculation of bill amount differs for each type of
customer. Guests needs to pay a delivery charge of $2. Regular customers get a
discount of 5%. Premium customers get a discount of 8% and they can use
membership card points for paying the bill.

Since the final amount calculation which is done in the payBill() of parent Customer
class will not suit for all the customer types, we need to have separate
implementation for this method in each of the child classes with respect to each
customer type.

So, in this scenario, the payBill() of the child classes will override the

implementation of payBill() present in the parent class. This is said to be method

overriding.

EG: public class Customer {

private String customerId;

private String customerName;


private long contactNumber;

private Address address;

public Customer(String customerId, String customerName, long contactNumber,

Address address) {

this.customerId = customerId;

this.customerName = customerName;

this.contactNumber = contactNumber;

this.address = address;

public double payBill(double totalPrice) {

System.out.println("Final bill for the customer is calculated here");

return totalPrice;

// displayCustomerDetails()

// updateDetails() overloaded methods

// getter and setter methods

}
In the below code, payBill() is overridden in the RegularCustomer to include

the 5% discount. Eg: public class RegularCustomer extends Customer {

private float discountPercentage; public RegularCustomer(String

custId, String custName, long mobileNo,

Address address) {

super(custId, custName, mobileNo, address);

this.discountPercentage = 5.0f;

@Override

public double payBill(double totalPrice)

{ double priceAfterDiscount =

totalPrice* (1 (discountPercentage / 100));

return priceAfterDiscount;

// getter and setter methods

}
We will now see how these overridden methods can be invoked. Consider the
Tester class given
below:
Eg: public class Tester {
public static void main(String[] args)

// Customer object created

Customer customer = new Customer("C101", "Stephen Abram",

7856341287L, new Address("D089", "St. Louis Street",

"Springfield", 62729));

// payBill() is invoked

double amount = customer.payBill(40.0);

System.out.println("Final bill amount is $" + (int) (amount * 100)/ 100.0);

Which method do you think will be invoked?

In the above case, payBill() from the parent class Customer will be invoked and the
output will be:

Final bill for the customer is calculated here

Final bill amount is $40.0

Now consider the below code:

Eg : //Regular Customer object created

RegularCustomer regularCustomer = new RegularCustomer("C101",

"Stephen Abram", 7856341287L, new Address("D089",

"St. Louis Street", "Springfield", 62729));


// payBill() is invoked double amount =

regularCustomer.payBill(40.0);

System.out.println("Final bill amount is $" + (int) (amount * 100)/ 100.0);

Which method do you think will be invoked in this case?

In the above case, payBill() of the child class RegularCustomer will be invoked and
the output will be:

Final bill amount is $37.99

Now, consider another case of calling an overridden method.


Eg:
Customer regularCustomer = new RegularCustomer("C101", "Stephen Abram",
7856341287L,
new Address("D089", "St. Louis Street",
"Springfield", 62729));
double amount =

regularCustomer.payBill(40.0);

Which method do you think will be invoked in

this case?

The answer is payBill() of the child class RegularCustomer.

You will now understand the reason behind the output of the previous code.

A parent class reference can refer to a child class object.


Only the overridden methods can be called using the parent class reference. Any
new method created in the child class will not be accessible using the parent class
reference.

The version of the method that will be called is determined by the object, and this
decision is taken at runtime. This is called Dynamic binding.

Static methods are not overridden. They will be called based on the type of
reference used.

Note: When a base class is specialized into child classes, instantiating the base class
is not a good practice.

ANNOTATIONS

Have you noticed that @Override is mentioned on top of the overridden methods?

This is called an annotation. It is like an information for the compiler or JVM and
provides additional meaning to the code.

An annotation is a meta-data that provides data about the program and is not part
of the program itself.

Its purpose is to give additional information to the compiler, or for some


processing during compiletime or runtime. It can be added to classes, methods,
variables, parameters and packages.

The @Override annotation is used with methods which ensures that the method
is actually overriding a parent method. If it is used on a method which does not
override any parent method, a compilation error occurs.

What happens, if @Override annotation is not used with an overridden method?

While it is not required to use this annotation when overriding a method, it helps
to prevent errors. If a method marked with @Override fails to correctly override a
method from one of its super classes, the compiler generates an error.
Not having this annotation can cause warnings. But having this annotation with no
super class that has a same method signature will result in an error.

@Override annotation helps in avoiding refactoring errors. If the method in the


super class is renamed, but not the overridden method, then also it will give an
error. SUPPER KEYWORD

You have already seen that super keyword can be used to invoke the constructors
of parent class.

super keyword can also be used for

• invoking a parent class method from a child class method


• accessing a parent class instance variable in the child class in case there is a
variable in the child class also with the same name

Consider the PremiumCustomer class which is the child class of


RegularCustomer.While calculating the final bill to be paid for the premium
customer, discount needs to be applied but the discount value is different from
that of a regular customer.The code for PremiumCustomer class is as shown
below:

Eg:

class PremiumCustomer extends RegularCustomer {

public PremiumCustomer(String custId, String custName, long

mobileNo, Addressaddress) {

super(custId, custName, mobileNo, address);

this.setDiscountPercentage(8.0f);

@Override
public double payBill(double totalPrice)

{ double priceAfterDiscount =

totalPrice* (1 (this.getDiscountPercentage() /

100));

return priceAfterDiscount;

super is used in the child class constructor to call the

parent class constructor.

Now consider the payBill() method in which final bill is calculated after applying
discount.

The discount variable is initialized to the fixed value 8% in the constructor of the
PremiumCustomer class and the calculation of the bill amount is done in the
payBill method. The same calculation of applying discount is done in the payBill()
method of the parent class, i.e., RegularCustomer class.

This redundant calculation can be avoided by calling the parent class method in
the child class method using super. payBill() method of the PremiumCustomer
class will then look as follows:

@Override public double payBill(double

totalPrice) { double priceAfterDiscount =

super.payBill(totalPrice); return

priceAfterDiscount;

}
.Here, payBill() method of the RegularCustomer will be called where the final bill
amount will be
calculated and returned to the payBill() method of the
PremiumCustomer class.
Let us have a look at one more code

snippet. Eg: public class Employee {

public float salary = 25000f; //

Other fields and methods

public class Manager extends

Employee {

private float salary; private

float bonus; public void

calculateSalary() { this.salary

= super.salary + bonus;

public void getBonus() {

return bonus;

public void setBonus(float bonus) {

this.bonus = bonus;
}

public void getSalary() {

return salary;

public void setSalary(float salary) {

this.salary = salary;

public class Tester {

public static void main(String[] args)

Manager manager = new Manager();

manager.setBonus(2000f);

manager.calculateSalary();

System.out.println("Manager Salary : " + manager.getSalary());

In the above given code, salary attribute is present in both the parent (Employee)
and the child (Manager) but the salary component of Manager class will be having
an additional component of bonus. In order to calculate the actual salary of the
manager, fixed salary of the Employee class is required.

Thus, in order to access the instance variable of the parent class inside the child
class, super is used.
Comparison of Method Overloading and Method Overriding
COMPARISON BETWEEN OVERLOADING AND OVERRIDING:

• Method overloading is a feature through which a class can have multiple


methods with the same name but different signature.
• Method overriding is a feature that allows a subclass or child class to have a
method with the same name and signature as that of the parent class.

• Method overloading is a feature through which a class can have multiple


methods with the same name but different signature.
• Method overriding is a feature that allows a subclass or child class to have a
method with the same name and signature as that of the parent class.

OBJECTS AND WRAPPER CLASS

Object Class :

By now, you know about inheritance and polymorphism.


One more thing that you should be knowing is that in Java, there is an Object class
which is the implicit super class of all classes.

It provides useful methods which can be overridden according to our requirement.

Some of the commonly used methods of the Object class are:

• equals()
• hashCode()
• toString()

equals method :

To understand the importance of the methods of Object class, let us consider the
scenario of SwiftFood. While adding food items, it is better to check if the
same food item is not being added twice.

Two food items are considered to be the same if their name and type are same.

Let us compare two Food objects using the == operator in the next Tryout.

Equals method :
WHY ARE THE OBJECTS IN THE PREVIOUS TRY OUT CODE DIFFERENT, EVEN
THOUGH THE VALUES OF THE MEMBER VARIABLES ARE SAME?

THE == OPERATOR WHICH IS USED TO COMPARE TWO FOOD OBJECTS COMPARES


THE OBJECTS WITH RESPECT TO THEIR MEMORY ADDRESS.

THUS, EVEN THOUGH THEY HAVE THE SAME VALUES OF MEMBER VARIABLES,
THEY ARE TWO DIFFERENT OBJECTS POINTING TO TWO DIFFERENT MEMORY
LOCATIONS.

WHENEVER TWO OBJECTS ARE TO BE COMPARED BASED ON THE VALUES OF THE


MEMBER VARIABLES, EQUALS() METHOD OF OBJECT CLASS CAN BE OVERRIDDEN.

• EQUALS() COMPARES OBJECTS TO CHECK FOR EQUALITY


• BY DEFAULT, EQUALS() USES MEMORY ADDRESS TO COMPARE OBJECTS FOR
EQUALITY (JUST LIKE ==)
• TO MAKE IT WORK FOR DIFFERENT REQUIREMENTS, IT NEEDS TO BE
OVERRIDDEN IN THE CLASSES

EG: // EQUALS METHOD OF OBJECT CLASS OVERRIDDEN FOR COMPARING TWO


FOOD OBJECTS

// based on foodName and foodType

public boolean equals(Object obj) {

Food otherFood = (Food) obj;

if (this.foodName.equals(otherFood.foodName)) {

if (this.foodType.equals(otherFood.foodType))

return true;

return false;

In the above scenario,


• equals() returns true if the foodName and foodType of two Food objects are
same
• type casting is done for the received object to cast it to Food object
• otherFood represents the second Food object received and is compared with
the Food object using which equals() is invoked

HASH CODE METHOD :

Next, you will see the hashCode() method.

• hashCode() uses an object's data to generate a hash value, which should be


a 32 bit integer
• By default, it derives the hash value based on the memory address of the
object being used
• If two objects are equal according to the equals() method, hashCode() must
produce the same integer value for the two objects
• it is important to understand that if the hash codes of two objects are same,
it doesn't prove that the objects are equal, i.e., it is possible for two unequal
objects to have the same hash codes.
• hashcode() uses a formula to generate an integer based on the same
attribute
• any formula can be used for generating the hash code as long as it generates
the same value for same objects

EG : // hashCode method overridden

public int hashCode() {

int result = 1;

result = result + (foodName.hashCode());

return result;

In the code snippet of equals() and in the code snippet given over here for
hashCode(), equals() and hashCode() are applied on String.

The String class is also a subclass of the Object class. It already overrides the
equals() and hashCode() methods.
Note: While comparing String objects for equality, equals() method should be used
since it is already overridden to compare the values.

TO-STRING METHOD :

Apart from equals() and hashCode(), the Object class provides another method
named toString().

The toString() method returns a textual representation of an object.

By default, it returns a string consisting of the name of the object's class, the '@'
character, and the unsigned hexadecimal representation of the hash code of the
object. E.g. - Food@af7d0676

It should be overridden to provide a meaningful textual representation.

The returned text should be concise, easy to read and informative.

Eg: public String toString() {

WRAPPER CLASS

Let us revisit the Object class hierarchy in java


The primitive data types in Java do not inherit the Object class as they are not
classes but sometimes, it is required to convert data types into objects in Java
programming.

To convert data types into objects and to inherit the Object class, Java has Boolean,
Character, Integer, Long, Float and Double classes which are called as Wrapper
Class.

Wrapper classes help in representing the primitive data types as an object. They
form a wrapping around the primitive values to represent them as objects.

They belong to the java.lang package as part of the Java library.

Wherever, the data type is required as an object, the objects of the Wrapper
classes can be used. Wrapper classes include methods to unwrap the object and
give back the data type.

The tryout provided next will give you a better understanding of Wrapper classes.

ABSTRACT KEYWORD

NEED FOR ABSTRACT :

Customer class in the SwiftFood app scenario has a payBill method. The
implementation of this method completely depends on the type of customer. So,
we implemented this method in all our customer types (child classes) by overriding
the parent method.
Thus, the parent class method implementation doesn’t actually have any
significance but it is necessary for all the child classes to provide a proper
implementation for the method.

So, this means the parent class Customer will not have any implementation for the
payBill method but we need to enforce that the child classes implement the
payBill() method.

This can be enforced with the help of abstract keyword as shown below.

Eg:

abstract public class Customer {

// Instance variables and constructor

public abstract double payBill(double totalPrice);

// displayCustomerDetails()

// updateDetails() overloaded methods

// getter and setter methods

Here, the method payBill doesn’t have any implementation because it depends on
the customer type, whether it is a guest, regular customer or premium
customer.Since it cannot have any implementation, it has been marked as
abstract.Since the method payBill is abstract in the Customer class, the class itself
becomes incomplete and demands for a child class to complete it.For marking the
class as incomplete, abstract keyword is used with the class also. Any class
extending this abstract class must provide the implementation of the abstract
methods.

ABSTRACT CLASS AND METHODS :

The abstract keyword signifies that something is not complete. It can be used with
classes and methods.

An abstract method is a method without any definition, i.e., the body. The
signature of an abstract method must be preceded by the abstract keyword.
EG: public abstract double payBill(double totalPrice);

An abstract class is a class which is incomplete and cannot be instantiated.

EG: abstract public class Customer {}

EG: Some points that you should be knowing about abstract class are:

• An abstract class encapsulates the common behaviors of all its child classes
with the help of abstract methods
• Concrete (non-abstract) classes which extend an abstract class must
implement all the abstract methods. Otherwise, they should be made
abstract as well.
• If a class contains at least one abstract method, the class should be abstract.
• A class can be made abstract even without any abstract methods.

ABSTRACTION AND DYNAMIC BINDING :

We know a parent class reference can refer to a child class object. So, if a reference
belongs to an abstract class, you can be sure that the object it refers to will always
be of its child type.

Thus, abstract classes enforce inheritance (since they can’t be


instantiated)andabstract methods enforce overriding (since they are incomplete
with no implementation).

INTERFACE

INTRODUCTION TO INTERFACE :

You know that the Premium customers are provided with a membership card using
which they can redeem points. Such membership cards can be provided by several
businesses to their customers and not just by SwiftFood app. This calls for setting
a contract which can be followed by all the businesses who want to provide
membership cards.

This setting up of contract can be implemented by using Interfaces in object


oriented programming.
An interface is used to define a generic template which can be implemented by
various classes.

• It contains method signatures and constant declarations


• The methods declared in an interface are implicitly public and abstract and
the data fields are implicitly public, static and final, i.e., constants
• An interface can extend more than one interface and a class can implement
more than one interface. This can be used to simulate multiple inheritance
in Java
• A class can extend from only one class but can implement any number of
interfaces
• The implements keyword is used to implement an interface. The classes
implementing an interface must implement all the specified methods.
Otherwise, they should be made abstract
• An interface creates a type. Hence, its reference can be used to refer to the
objects of the classes which implement that interface. This leads to dynamic
binding
• Since Java 8, an interface can also have default and static methods. This is
not discussed in this course

Observe the below code. The interface specifies the behaviors by declaring
methods but does not provide the implementations. Using interface, we specify
what is to be done without telling how

EG: public interface PremiumCards {

int WELCOME_POINTS = 100;

double redeemPoints(double totalPrice);

void addPoints(double money);

Observe the below code of Regular Customer class. The RegularCustomer extends
the Customer class.

EG: public class RegularCustomer extends Customer {

protected float discountPercentage;

public RegularCustomer(String custId, String custName, long mobileNo,


Address address) {

super(custId, custName, mobileNo, address);

this.discountPercentage = 5.0f;

public float getdiscountPercentage() {

return discountPercentage;

public void setdiscountPercentage(float discountPercentage) {

this.discountPercentage = discountPercentage;

@Override

public double payBill(double totalPrice) {

double priceAfterDiscount = totalPrice

* (1 - (discountPercentage / 100));

return priceAfterDiscount;

Premium customers are special types of regular customers and hence must extend
the RegularCustomer class. Premium customers also have membership cards and
hence must also implement the interface PremiumCards.

The PremiumCustomer class which implements the PremiumCards interface has


to override and provide the implementations of the methods of the interface.
Thus, interfaces are used to enforce standard rules or contracts.

Eg: public class PremiumCustomer extends RegularCustomer implements


PremiumCards {
private int rewardPoints = WELCOME_POINTS;

public PremiumCustomer(String custId, String custName, long mobileNo,

Address address) {

super(custId, custName, mobileNo, address);

this.discountPercentage = 8.0f;

@Override

public double redeemPoints(double totalPrice) {

double amountDeducted = checkAvailablePoints(totalPrice) ?


totalPrice

: this.rewardPoints;

this.rewardPoints = this.rewardPoints

- (int) Math.round(amountDeducted);

System.out.println((int) Math.round(amountDeducted)

+ " points deducted for paying the bill");

System.out.println(this.rewardPoints + " points remaining");

return amountDeducted;

@Override

public void addPoints(double money) {

int pointsAdded = (int) money / 10;

this.rewardPoints += pointsAdded;

System.out.println(pointsAdded + " points added for your purchase");


System.out.println(this.rewardPoints + " points remaining");

@Override

public double payBill(double totalPrice) {

double priceAfterDiscount = super.payBill(totalPrice);

System.out.println("Total cost after discount: " + priceAfterDiscount);

addPoints(priceAfterDiscount);

totalPrice = priceAfterDiscount - redeemPoints(priceAfterDiscount);

return totalPrice;

public boolean checkAvailablePoints(double amountToBePaid) {

if (this.rewardPoints >= Math.round(amountToBePaid)) {

return true;

return false;

public int getRewardPoints() {

return rewardPoints;

public void setRewardPoints(int rewardPoints) {

this.rewardPoints = rewardPoints;

}
Tester class

Eg: public class Tester {

public static void main(String[] args) {

Address custAddress = new Address("D089", "St. Louis Street",

"Springfield", 62729);

Customer premiumCustomer = new PremiumCustomer("C1016",

"Stephen Abram", 7856341287L, custAddress);

premiumCustomer.displayCustomerDetails();

double amountRemaining = premiumCustomer.payBill(140);

System.out.println("Final amount to be paid " + amountRemaining);

EXCEPTION

What is Exception?

The previous Tryout results in runtime error as shown below:

The code stops abruptly because of dividing the sum with totalSubjects whose
value is 0.

Consider one more implementation of calculateAverageMarks() method as shown


below.

Eg: public void calculateAverageMarks() {

int sum = 0;

int totalSubjects = 0;
for (int i = 0; i <= marks.length; i++) {

sum += marks[i];

this.averageMarks = sum / totalSubjects;

System.out.println("Average Marks : " + this.averageMarks);

The above code will also result in a runtime error as shown below.

In case of both the errors, the error messages are not user friendly and also
technical details are provided in the error messages which could be risky. It would
be better if user-friendly and meaningful error messages can be shown to the end
user.This can be done by handling the errors properly.The runtime errors shown
previously are called as exceptions and the process of handling the exceptions is
known as Exception Handling.You will now understand how to handle exceptions.

TRY CATCH BLOCK

In order to handle exceptions, the first step is to identify the code which may
generate exceptions. The set of statements that may generate an exception are
enclosed in a block known as try block. The try block contains a set of statements
where an exception can occur.

The second step is to handle those exceptions. In order to handle those exceptions
which get raised in the try block, we use the catch block. A catch block is where
you handle the exceptions, i.e., the catch block specifies what is to be done when
an exception occurs.

A try block is always followed by a catch block.

Syntax:

Eg: try
{

// statements that may cause an exception

catch (exceptionType e)

// error handling code

We will now handle the divide by zero exception that we had encountered before
using try catch block.

Multiple catch blocks - ScenarioIn the previous tryout, we have handled the issue
of divide by zero exception by using the try-catch block.

Replace the calculateAverageMarks() in the previous tryout with the below


method implementation. Try out the updated code and observe the output.

Eg : public void calculateAverageMarks() {

int sum = 0;

int totalSubjects = 0;

try {

for (int i = 0; i <= marks.length; i++) {

++totalSubjects;

sum += marks[i];

this.averageMarks = sum / totalSubjects;

System.out.println("Average Marks: " + this.averageMarks);

} catch (ArithmeticException e) {
System.out.println("Divide by Zero exception occurred!");

You would observe that even after using the try-catch block, the program is getting
terminated abruptly and an exception is getting raised as shown below.

WHY DO WE GET THIS ERROR EVEN AFTER USING A TRY-CATCH BLOCK?

This is because the present catch block can handle


only ArithmeticException whereas the current implementation of
calculateAverage() encounters ArrayIndexOutOfBoundsException. In order to
resolve this exception, we have to create one more catch block having the
exception type as ArrayIndexOutOfBoundsException.

In Java, a single try block can have several catch blocks associated with it. You can
catch different exceptions in different catch blocks. When an exception occurs in
the try block, one of the corresponding catch blocks that handles that particular
exception executes. For example, if an arithmetic exception occurs in try block
then the statements enclosed in the catch block for arithmetic exception executes.

Eg: catch(ArrayIndexOutOfBoundsException e) {

//This block will only execute if any ArrayIndexOutOfBoundsException occurs


in try block

System.out.println("Array index out of range exception occurred!");

After adding the above catch block in the calculateAverageMarks() method, the
program will not display the system generated exception message. Instead, it will
display the user-defined message.

Can we predict all the exceptions that can occur in a program?


It is nearly difficult to predict all the possible exceptions and write the
corresponding catch blocks. Then how can we catch the exception for which we
don’t have corresponding catch block?

Suppose we want to display the length of the student name in calculateAverage()


and let us assume that studentName is not yet initialized.

This will result in NullPointerException.

In order to catch an exception for which the corresponding catch block is not
present in the program, we can use the generic exception catch block.

Syntax:

catch(Exception e) {

//This block can handle all types of exceptions

System.out.println("Some error occurred");

The generic exception handler can handle all types of exceptions, therefore, it
should be placed at the end of all the catch blocks.

Eg: catch(ArithmeticException e) {

//This block will only execute if any Arithmetic exception occurs in try block

System.out.println("Divide by Zero exception occurred!");

catch(ArrayIndexOutOfBoundsException e) {

//This block will only execute if any ArrayIndexOutOfBoundsException occurs


in try block

System.out.println("Array index out of range exception occurred!");

}
catch( Exception e) {

//This block will handle all types of exceptions that occur in try block

System.out.println("Some error occurred!");

If you will try to place the generic catch block at any other place (start or middle)
of the catch blocks, then it will result in a compilation error.

Eg: catch(ArithmeticException e) {

//This block will only execute if any Arithmetic exception occurs in try block

System.out.println("Divide by Zero exception occurred!");

catch(Exception e) {

//This block will handle all types of exceptions that occur in try block

System.out.println("Some error occurred!");

catch(ArrayIndexOutOfBoundsException e) {

//This block will only execute if any ArrayIndexOutOfBoundsException occurs


in try block

System.out.println("Array index out of range exception occurred!");

This way of defining the catch block will result in a compilation error as shown
below.

NESTED TRY CATCH BLOCK

When a try-catch block is present inside another try block then it is called a nested
try-catch block.
The syntax of nested try-catch is given below:

Eg: //main try block

try{

statement 1;

statement 2;

//nested try-catch block

try{

statement 3;

catch(Exception ex){

//exception message

catch(Exception ex){

//exception message

If the inner catch block is not able to handle the exception raised in the inner try
block, then the execution moves to the outer catch block.

Take a look at the below code to understand how nested try-catch works.

EG: public void calculateAverageMarks() {

int sum=0;

int totalSubjects=0;

//outer try block


try {

//inner try block

try {

for (int i = 0; i <marks.length;i++) {

sum+=marks[i];

this.averageMarks=sum/totalSubjects;//Exception will be
raised as totalSubjects is 0

System.out.println("Average Marks: "+ this.averageMarks);

//inner catch block

catch(ArithmeticException e) {

//This block will only execute if any Arithmetic exception occurs in try block

System.out.println("Divide by Zero exception occurred!");

catch(ArrayIndexOutOfBoundsException e) {

//This block will only execute if any


ArrayIndexOutOfBoundsException occurs in try block

System.out.println("Array index out of range exception occurred!");

//outer catch block

catch(Exception e) {
//This block will handle all types of exceptions that occur in try
block

System.out.println("Some error occurred!");

TYPES OF EXCEPTIONS;

MODE OF GENERATION:

By now, you have understood how to handle exceptions.

Let us now try to know few more things about exceptions.

Exceptions get generated mainly in two ways:

• Automatically by the compiler or JVM when an exceptional situation is


detected or has occurred.

Usually, a certain input or a programming mistake or an overlook can lead to such


exceptions

E.g.:

int z = x/y;

// ArithmeticException if y is 0

int num = numArray[i];

// ArrayIndexOutOfBoundsException if i exceeds the array capacity

• Manually by the programmer to denote exceptional situations as defined by


the business

For example, invalid payment mode is an exception and hence, this situation needs
to be denoted manually.

are forced

You might also like