Java Lex 2 3
Java Lex 2 3
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.
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.
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.
int x = 20;
int y = 10;
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.
customer.contactNumber = 9786758497L;
System.out.println(customerOne.contactNumber);
customerOne.updateContact(customerOne);
System.out.println(customerOne.contactNumber);
OUTPUT:
CONSTRUCTORS
SENERIO:
customer1.customerId = "C101";
customer1.customerName = "Jack";
customer1.contactNumber = 9870345687L;
customer2.customerId = "C102";
customer2.customerName = "Jane";
customer2.contactNumber = 7870098687L;
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:
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:
//body
PARAMETERLESS CONSTRUCTOR
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.
You can also create parameterless constructor in a class. In this case, Java does
not create a separate default constructor.
EG: class Customer {
public Customer() {
System.out.println("Constructor called");
System.out.println(customer1.customerId);
System.out.println(customer1.customerName);
System.out.println(customer1.contactNumber);
System.out.println(customer1.address);
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 {
customerId = cId;
customerName = cName;
contactNumber = contact;
address = add;
The parameter values need to be passed while creating the object as shown
below.
Eg:
System.out.println(customer1.customerId);
System.out.println(customer1.customerName);
System.out.println(customer1.contactNumber);
System.out.println(customer1.address);
EG:
class Customer {
public Customer() {
customerId = cId;
customerName = cName;
contactNumber = contact;
address = add;
THIS KEYWORD
SCENARIO :
Eg:
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.
Eg:
public Customer() {
String address) {
this();
this.customerId = customerId;
this.customerName = customerName;
this.contactNumber = contactNumber;
this.address = address;
this.displayCustomerName();
this can also be used to invoke method or constructor of the current object.
Eg ;
public class Customer {
public Customer() {
this();
this.customerId = customerId;
this.customerName = customerName;
this.contactNumber = contactNumber;
this.address = address;
this.displayCustomerName();
MEMORY MANAGEMENT
Till now you have learnt the basic concepts of OOP but have you wondered how
Java manages object creation in the memory?
Eg:
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?
MEMORY ALLOCATION :
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.
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.
You might be wondering when does an object not have any reference and become
eligible for garbage collection?
• When the reference variable pointing to the object is initialized to null, the
object will not have any reference.
Eg:
// Object creation
customerObj = null;
}
GARBAGE COLLECTION - CASE 2
// Object creation
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 {
System.out.println();
customer.customerId = "C101";
customer.contactNumber = 7856341287L;
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:
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.
EG:
account.balance();
ACCESS MODIFIERS
So far, you have been using "public" and "private" keywords in your code. These
keywords are called access modifiers.
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.
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:
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
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.
Eg :
class Customer {
String address) {
this.customerId = customerId;
this.customerName = customerName;
this.contactNumber = contactNumber;
this.address = address;
return customerId;
this.customerId = customerId;
return customerName;
this.customerName = customerName;
return contactNumber;
this.contactNumber = contactNumber;
return address;
}
public void setAddress(String address) {
this.address = address;
System.out.println();
double discountPercentage = 5;
return priceAfterDiscount;
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 {
this.customerId = customerId;
this.customerName = customerName;
this.contactNumber = contactNumber;
this.address = address;
this.deliveryCharge = deliveryCharge;
this.customerId = customerId;
return customerName;
this.customerName = customerName;
return contactNumber;
this.contactNumber = contactNumber;
return address;
this.address = address;
}
public void displayCustomerDetails() {
System.out.println();
double discountPercentage = 5;
return finalBillAmount;
}
}
Eg :
String address) {
this.customerId = customerId;
this.customerName = customerName;
this.contactNumber = contactNumber;
this.address = address;
this.deliveryCharge = 1.5f;
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.
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.
Syntax:
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 :
One way to initialize the static variable is to initialize at the time of declaration as
shown below
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 {
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 {
static {
deliveryCharge = 1.5f;
String address) {
this.customerId = customerId;
this.customerName = customerName;
this.contactNumber = contactNumber;
this.address = address;
return customerId;
this.customerId = customerId;
return customerName;
this.customerName = customerName;
}
return contactNumber;
this.contactNumber = contactNumber;
return address;
this.address = address;
System.out.println();
double discountPercentage = 5;
System.out.println("Calculating final amount to be paid.....");
return finalBillAmount;
STATIC METHOD
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
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 :
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.
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 :
return deliveryCharge;
Customer.deliveryCharge = deliveryCharge;
Eg:
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.
IMPLEMENTATION OF STATIC
The following code shows the implementation of Customer class with static
variables, static blocks and static methods.
EG:
class Customer {
static {
deliveryCharge = 1.5f;
this.customerId = customerId;
this.customerName = customerName;
this.contactNumber = contactNumber;
this.address = address;
return customerId;
this.customerId = customerId;
return customerName;
this.customerName = customerName;
return contactNumber;
this.contactNumber = contactNumber;
return address;
}
this.address = address;
return deliveryCharge;
Customer.deliveryCharge = deliveryCharge;
System.out.println();
return finalBillAmount;
Customer.setDeliveryCharge(2f);
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
static {
deliveryCharge = 1.5f;
this.customerName = customerName;
this.contactNumber = contactNumber;
this.address = address;
return counter;
return customerId;
this.customerId = customerId;
return customerName;
this.customerName = customerName;
return contactNumber;
this.contactNumber = contactNumber;
return address;
}
public void setAddress(String address) {
this.address = address;
return deliveryCharge;
Customer.deliveryCharge = deliveryCharge;
System.out.println();
double discountPercentage = 5;
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:
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.
IMPLEMENTATION OF AGGREGATION :
Let us now consider the SwiftFood app. Consider the Order and Food class
Eg:
this.orderId = orderId;
this.orderedFoods = orderedFoods;
this.status = "Ordered";
}
}
Eg :
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 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 :
food.setCuisine("Italian");
food.setFoodType("Veg");
food.setQuantityAvailable(10);
food.setUnitPrice(8.0);
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 Order() {
this.status = "Ordered";
this.orderId = orderId;
this.orderedFoods = orderedFoods;
this.status = "Ordered";
return Order.orderIdCounter-100;
return orderedFoods;
this.orderedFoods = orderedFoods;
}
//other methods
double foodPrice = 0;
double finalPrice = 0;
foodPrice+=food.getUnitPrice()*1;
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 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:
System.out.println(food.getFoodName());
return true;
You can test the method by writing the below code in main:
Eg :
public static void main(String[] args) {
food1.setFoodName("Hamburger");
food1.setFoodType("Non-Veg");
food1.setCuisine("American");
food1.setUnitPrice(3.8);
food1.setQuantityAvailable(20);
food2.setFoodType("Veg");
food2.setCuisine("American");
food2.setUnitPrice(20);
food2.setQuantityAvailable(25);
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
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 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
//Child/Sub/Derived class
//Child/Sub/Derived class
EG:
class Employee {
// Parent/Super/Base class
// Child/Sub/Derived class
// 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() {
System.out.println("Creating a customer...");
public RegularCustomer() {
// 1: This line will be executed first and the flow will go to [2]
Eg:
class Customer {
this.customerId = customerId;
this.customerName = customerName;
public Customer() {
return customerId;
}
public void setCustomerId(String customerId) {
this.customerId = customerId;
return customerName;
this.customerName = 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:
this.setCustomerId(custId);
this.setCustomerName(custName);
this.discount = 5.0f;
System.out.println("Child Constructor");
return 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:
regularCustomer.displayCustomerDetails();
}
Output :
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
}
}
TYPES OF INHERITANCE
1) Single Inheritance :
There are multiple types of inheritance. We will be discussing some of them in this
course.
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.
// Parent/Super/Base class
// Child/Sub/Derived class
}
2) Multilevel Inheritance :
//code
//code
//code
}
3) 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.
// code here
// code here
// 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.
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).
Eg:
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.
STATIC POLYMORPHISM
Method overloading allows the programmer to have multiple methods with the
same name in the same class, but differing in their signature.
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
this.setContactNumber(mobile);
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.
mobile) {
this.setContactNumber(mobile);
}
public void updateDetails(Address address) {
this.setAddress(address);
}
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);
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 :
private String
customerName; private
long contactNumber;
// Parameterless
constructor public
Customer() {
// Parameterized constructor
contactNumber,
Address address) {
this.customerId = customerId;
this.customerName = customerName;
this.contactNumber = contactNumber;
this.address = address;
// Parameterized constructor
address) {
this.customerName =
customerName;
this.contactNumber = contactNumber;
this.address = address;
Exception {
/*
Parameterless constructor will be invoked, instance
*/
/*
*/
/*
*/
"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.
• 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.
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
overriding.
Address address) {
this.customerId = customerId;
this.customerName = customerName;
this.contactNumber = contactNumber;
this.address = address;
return totalPrice;
// displayCustomerDetails()
}
In the below code, payBill() is overridden in the RegularCustomer to include
Address address) {
this.discountPercentage = 5.0f;
@Override
{ double priceAfterDiscount =
return priceAfterDiscount;
}
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)
"Springfield", 62729));
// payBill() is invoked
In the above case, payBill() from the parent class Customer will be invoked and the
output will be:
regularCustomer.payBill(40.0);
In the above case, payBill() of the child class RegularCustomer will be invoked and
the output will be:
regularCustomer.payBill(40.0);
this case?
You will now understand the reason behind the output of the previous code.
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.
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.
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.
You have already seen that super keyword can be used to invoke the constructors
of parent class.
Eg:
mobileNo, Addressaddress) {
this.setDiscountPercentage(8.0f);
@Override
public double payBill(double totalPrice)
{ double priceAfterDiscount =
totalPrice* (1 (this.getDiscountPercentage() /
100));
return priceAfterDiscount;
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:
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
Employee {
calculateSalary() { this.salary
= super.salary + bonus;
return bonus;
this.bonus = bonus;
}
return salary;
this.salary = salary;
manager.setBonus(2000f);
manager.calculateSalary();
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:
Object Class :
• 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?
THUS, EVEN THOUGH THEY HAVE THE SAME VALUES OF MEMBER VARIABLES,
THEY ARE TWO DIFFERENT OBJECTS POINTING TO TWO DIFFERENT MEMORY
LOCATIONS.
if (this.foodName.equals(otherFood.foodName)) {
if (this.foodType.equals(otherFood.foodType))
return true;
return false;
int result = 1;
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().
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
WRAPPER CLASS
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.
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
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:
// displayCustomerDetails()
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.
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);
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.
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.
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.
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
Observe the below code of Regular Customer class. The RegularCustomer extends
the Customer class.
this.discountPercentage = 5.0f;
return discountPercentage;
this.discountPercentage = discountPercentage;
@Override
* (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.
Address address) {
this.discountPercentage = 8.0f;
@Override
: this.rewardPoints;
this.rewardPoints = this.rewardPoints
- (int) Math.round(amountDeducted);
System.out.println((int) Math.round(amountDeducted)
return amountDeducted;
@Override
this.rewardPoints += pointsAdded;
@Override
addPoints(priceAfterDiscount);
return totalPrice;
return true;
return false;
return rewardPoints;
this.rewardPoints = rewardPoints;
}
Tester class
"Springfield", 62729);
premiumCustomer.displayCustomerDetails();
EXCEPTION
What is Exception?
The code stops abruptly because of dividing the sum with totalSubjects whose
value is 0.
int sum = 0;
int totalSubjects = 0;
for (int i = 0; i <= marks.length; i++) {
sum += marks[i];
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.
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.
Syntax:
Eg: try
{
catch (exceptionType e)
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.
int sum = 0;
int totalSubjects = 0;
try {
++totalSubjects;
sum += marks[i];
} 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.
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) {
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.
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) {
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
catch(ArrayIndexOutOfBoundsException e) {
}
catch( Exception e) {
//This block will handle all types of exceptions that occur in try block
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
catch(Exception e) {
//This block will handle all types of exceptions that occur in try block
catch(ArrayIndexOutOfBoundsException e) {
This way of defining the catch block will result in a compilation error as shown
below.
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:
try{
statement 1;
statement 2;
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.
int sum=0;
int totalSubjects=0;
try {
sum+=marks[i];
this.averageMarks=sum/totalSubjects;//Exception will be
raised as totalSubjects is 0
catch(ArithmeticException e) {
//This block will only execute if any Arithmetic exception occurs in try block
catch(ArrayIndexOutOfBoundsException e) {
catch(Exception e) {
//This block will handle all types of exceptions that occur in try
block
TYPES OF EXCEPTIONS;
MODE OF GENERATION:
E.g.:
int z = x/y;
// ArithmeticException if y is 0
For example, invalid payment mode is an exception and hence, this situation needs
to be denoted manually.
are forced