Object Oriented Programming
in Java
Object Oriented Programming (OOP):-
Object Oriented Programming v/s Procedural Programming
Difference Between Java and C++ in Terms of Language Functions
Java Virtual Machine (JVM)
Key Roles of the JVM
Compilation and Interpretation in Java
Advantages of JVM and Compilation-Interpretation Model
Object v/s Object Reference:-
Main Characteristics of an OOP Language
1. Encapsulation
2. Abstraction
3. Inheritance
4. Polymorphism
Summary Table:-
Data Encapsulation v/s Data Abstraction
Association, Aggregation and Composition in OOP:-
Association
Aggregation
Composition
Differences between Association, Aggregation, and Composition
Link and Association
Basic Concepts in OOP
public static void main (String[] args)
1. public
2. static
3. void
4. main
5. String[] args
Example of main Method
Parameter Passing in Programming
Call by Value:-
Call by Reference:-
static Keyword in Java
Static Variables
Static Methods
Object Oriented Programming in Java 1
Static Blocks
Static Nested Classes
Key Points about static in Java
static v/s final Keyword
Message Passing in OOP
Key Aspects of Message Passing
Example of Message Passing
Importance of Message Passing
Method Overloading
Garbage Collection in Java
finalize() Method in Java
Inheritance in Java
Types of Inheritance in OOP
Single Inheritance
Multiple Inheritance (Not supported with classes in Java)
Multilevel Inheritance
Hierarchical Inheritance
Hybrid Inheritance
super Keyword in Java
1. Accessing Superclass Methods with super
2. Accessing Superclass Constructors with super()
3. Accessing Superclass Fields with super
Key Points about super
Method Overriding
Given a method that does not declare any exception, can I override that method in
a subclass to throw an exception?
Covariant Return Type
Access Modifiers in Java
1. public
2. protected
3. private
4. default (no modifier)
Summary Table:-
Dynamic Method Dispatch:
Early Binding v/s Late Binding
Abstraction:-
Advantages of Abstraction:
Levels of Abstraction:
Example Code:
Applications:
Abstract Class v/s Interface
Object Oriented Programming in Java 2
Multiple Inheritance in Java
Packages in Java
Key Benefits of Using Packages
Declaring and Importing Packages
Java’s Package Structure
Exception Handling in Java
Key Concepts in Exception Handling
Exception Handling Keywords in Java
Basic Structure of Exception Handling
Example of Exception Handling
Types of Exceptions
Checked Exceptions
Unchecked Exceptions (Runtime Exceptions)
Errors
Advantages of Exception Handling
Custom Exceptions
Best Practices in Exception Handling
Chained Exceptions in Java
Purpose of Chained Exceptions
Syntax Example
Benefits of Chained Exceptions
Threading in Java
Key Concepts in Threading
Process v/s Thread
Multiprocessing v/s Multithreading
Creating Threads in Java
1. Extending the Thread Class
2. Implementing the Runnable Interface
Thread Life Cycle
Important Methods in Threading
Thread Synchronization
Inter-Thread Communication
Deadlock
Object Oriented Programming (OOP):-
Definition: Object Oriented Programming (OOP) is a programming paradigm
based on the concept of “objects”, which represent real world entities. Each
object can contain data (attributes) and methods (functions or behaviors) that
operate on the data.
Object Oriented Programming in Java 3
Core Principles: OOP revolves around four core principles:
Encapsulation: Bundling data and methods that operate on the data within
a single unit, or object, to protect data from outside interference.
Abstraction: Simplifying complex systems by modeling classes appropriate
to the problem and hiding unnecessary details.
Inheritance: Allowing new classes to derive properties and behaviors from
existing classes, promoting reusability.
Polymorphism: Enabling objects to be treated as instances of their parent
class, allowing methods to do different things based on the object type.
Modularity: OOP encourages breaking down programs into reusable objects,
making it easier to manage and understand large, complex systems.
Examples: Common OOP languages include Java, C++, Python, and C#.
Object Oriented Programming v/s Procedural Programming
Point of
Object Oriented Programming Procedural Programming
Differentiation
Focuses on functions/
Focuses on objects and classes,
Program procedures, organizing code
organizing code around real-
Structure around tasks or steps to be
world entities
completed
Encapsulates data within Data and functions are
Data handling objects, restricting access separate, often leading to less
through methods control over data access
Encourages reusability through Reusability is achieved through
inheritance and polymorphism, functions, but inheritance and
Reusability
allowing shared code across polymorphism are not inherent
related classes features.
More scalable and maintainable
Can become difficult to manage
Scalability and for large projects because it
as the codebase grows due to a
Maintainability provides a clear modular
lack of modular structure
structure
Lower level, focusing on
Higher level of abstraction as it
Abstraction Level functions and the sequence of
models real-world objects
tasks
Object Oriented Programming in Java 4
Difference Between Java and C++ in Terms of Language
Functions
Point of
Java C++
Differentiation
Platform-dependent; code is
Platform-independent, meaning
compiled into machine code
code is compiled into bytecode
Platform specific to the operating system,
that runs on the Java Virtual
Independence so executables need
Machine (JVM), making it cross-
recompilation for different
platform
platforms
Requires manual memory
Uses automatic garbage management using new and
Memory collection, where the JVM delete keywords, which gives
Management manages memory deallocation, the programmer more control but
reducing memory leaks increases the risk of memory
leaks
Does not support direct Supports pointers, allowing direct
manipulation of pointers for memory access and
Pointers
security and simplicity. Java manipulation, which can be
uses references instead powerful but also risky
Purely object-oriented, as every
Hybrid language; it supports both
element must be part of a class
Object-Oriented procedural and object-oriented
(except primitives); it follows the
Design programming, allowing a more
“write once, run anywhere”
flexible approach
philosophy
Java does not support multiple Supports multiple inheritance
inheritance with classes to avoid directly, allowing a class to inherit
Multiple
complexity and ambiguity. from multiple classes, which can
Inheritance
Instead, it provides interfaces to lead to complexities like the
achieve similar functionality “diamond problem”
Has a robust, consistent
exception-handling model with Also supports exception handling
Exception
try , catch , finally and with try , catch and throw ,
Handling
throw . It forces error handling but is less strict in enforcing it
for many issues at compile time
Standard Rich set of standard libraries, Has a Standard Template Library
Libraries especially for networking, (STL) for data structures and
threading, GUI, and utility algorithms, but fewer built-in
Object Oriented Programming in Java 5
Point of
Java C++
Differentiation
functions, making it easier to libraries compared to Java for
build applications quickly higher-level features
Compiles source code directly
Compiles source code into
into machine code, which
Compilation platform-independent bytecode
typically results in faster
Process which is then interpreted by the
execution times but less
JVM at runtime
portability
Java Virtual Machine (JVM)
The Java Virtual Machine (JVM) is an abstract machine that provides a
runtime environment for Java applications. It is part of the Java Runtime
Environment (JRE) and is responsible for executing Java bytecode, which is the
intermediate, platform-independent code generated after compilation. The JVM
is crucial in making Java platform-independent, meaning Java applications can
run on any system with a compatible JVM.
Key Roles of the JVM
1. Loads and Verifies Bytecode: The JVM loads the .class files (compiled
bytecode) and checks them for errors and security risks.
2. Executes Bytecode: Converts bytecode into machine-specific code using
an interpreter or a Just-In-Time (JIT) compiler.
3. Manages Memory and Resources: Allocates memory, manages the stack,
and handles garbage collection.
4. Provides a Secure Execution Environment: Ensures safe execution of
code, protecting the host system from malicious code.
Compilation and Interpretation in Java
Java is often described as both a compiled and interpreted language because
it uses a two-step process: compilation and interpretation.
Step 1: Compilation (Source Code to Bytecode
1. Java Compiler: The java compiler ( javac ) converts Java source code (in
.java files) into bytecode (in .class files).
Object Oriented Programming in Java 6
2. Platform Independence: This bytecode is platform-independent, meaning it
can run on any device with a compatible JVM.
3. Bytecode Characteristics: Bytecode is an optimized, intermediate form of
the code that is neither fully compiled nor directly executed by any
hardware. It serves as a universal format that the JVM can understand.
Example:
// Source code in HelloWorld.java
public class HelloWorld {
public static void main (String[] args) {
System.out.println("Hello, World");
}
}
The command javac HelloWorld.java compiles this code into HelloWorld.class ,
which contains platform-independent bytecode.
Step 2: Interpretation (Bytecode to Machine Code)
1. Class Loader: When the JVM executes the program, it first loads the .class
file into memory using the Class Loader.
2. Interpreter and Just-In-Time (JIT) Compiler:
Interpreter: The JVM interpreter reads and executes bytecode
instructions line by line. Interpretation is quick but can be slower during
repetitive execution.
Just-In-Time (JIT) Compiler: To enhance performance, the JVM uses a
JIT compiler to convert frequently executed parts of bytecode into
native machine code during runtime. This native code is stored and
reused, making future executions faster.
3. Execution: The native machine code is executed directly by them CPU,
completing the program’s execution on the target platform.
Summary of Compilation and Interpretation Process
1. Source Code (Java) → Bytecode (Compiled): javac compiles .java files to
.class files containing bytecode.
Object Oriented Programming in Java 7
2. Bytecode (Platform-Independent) → Machine Code
(Interpreted/Compiled by JVM): The JVM interprets and/or compiles
bytecode to machine code and executes it.
Advantages of JVM and Compilation-Interpretation Model
Platform Independence: Java code can run on any device with a
compatible JVM, making Java highly portable.
Performance Optimization: The JIT compiler improves performance by
compiling bytecode to native code as needed.
Security: The JVM provides a secure execution environment, protecting the
host machine from potential risks.
Object v/s Object Reference:-
1. Object:
An object is an instance of a class that occupies memory and holds
data.
It is created using the new keyword and represents an entity with
attributes (fields) and behaviors (methods).
Example:
Car myCar = new Car(); // Here, `new Car()` creates an o
2. Object Reference:
An object reference is a variable that points to or holds the address of
an object in memory.
It does not hold the actual data, just a reference (or pointer) to the
object.
Example:
Car myCar; // `myCar` is an object reference, initially
myCar = new Car(); // `myCar` now references a Car objec
Object Oriented Programming in Java 8
Difference:
An object is the actual data instance in memory, while an object
reference is the variable that points to the object’s location in memory.
Main Characteristics of an OOP Language
The main characteristics of an Object-Oriented Programming (OOP) language
are Encapsulation, Abstraction, Inheritance, and Polymorphism. These
concepts form the core of OOP, promoting code modularity, reusability, and
scalability.
1. Encapsulation
Definition: Encapsulation is the technique of bundling data (attributes) and
methods (functions) that operate on the data into a single unit, known as a
class. It restricts direct access to some components, which can protect the
integrity of the data.
Purpose: Encapsulation hides the internal state of an object and only
exposes selected attributes or behaviors to the outside. This ensures that
data is safe from unintended interference and misuse.
Example: Using private variables and providing public getter and setter
methods to access and update them.
public class Student {
private int age; // Encapsulated data
public int getAge() { // Controlled access
return age;
}
public void setAge (int age) {
this.age = age;
}
}
Object Oriented Programming in Java 9
2. Abstraction
Definition: Abstraction is the concept of hiding unnecessary details and
showing only essential information to the user. In OOP, abstraction focuses
on providing a simplified interface while hiding the underlying
implementation complexities.
Purpose: Abstraction reduces complexity and helps focus on higher-level
operations by exposing only the necessary parts of an object.
Example: Abstract classes and interfaces in Java are used to define
general behavior that can be implemented by concrete classes.
abstract class Animal {
abstract void sound(); // Abstract method
}
class Dog extends Animal {
void sound() {
System.out.println("Bark");
}
}
3. Inheritance
Definition: Inheritance is a mechanism that allows one class to inherit the
fields and methods of another class. The class that inherits is called the
subclass (or child class), and the class being inherited from is called the
super class (or parent class).
Purpose: Inheritance promotes code reuse by allowing new classes to
adopt the properties and behaviors of existing ones, reducing redundancy
Example: A Dog class can inherit from an Animal class, meaning that Dog
will have access to the methods and fields of Animal .
class Animal {
void eat() {
System.out.println("Animal eats");
}
Object Oriented Programming in Java 10
}
class Dog extends Animal {
void bark() {
System.out.println("Dog barks");
}
}
class Example {
public static void main (String args[]) {
Dog dog = new Dog();
dog.bark(); // The method of the Dog class
dog.eat(); // The inherited method from Animal
}
}
4. Polymorphism
Definition: Polymorphism allows a single method, action, or operator to
behave differently based on the object or context. In OOP, it refers to the
ability of different classes to respond to the same method call in their own
way.
Purpose: Polymorphism enables flexibility and dynamism in code, allowing
objects of different types to be treated as instances of a common
superclass.
Types:
Compile-time Polymorphism (Method Overloading): Allows a class to
have multiple methods with the same name but different parameters.
Runtime Polymorphism (Method Overriding): Allows a subclass to
provide a specific implementation of a method already defined in its
superclass.
Example:
class Animal {
void sound() {
System.out.println("Animal sound");
}
Object Oriented Programming in Java 11
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Bark");
}
}
class Example {
public static void main (String args[]) {
Dog dog = new Dog();
dog.sound();
// It will print `Bark` which indicates
// the method has been overridden
}
}
Summary Table:-
OOP
Description Purpose
Characteristic
Bundling data and methods, Protects data integrity, restricts
Encapsulation
hiding internal details access
Hiding complex details,
Reduces complexity, promotes a
Abstraction showing only essential
simpler interface
features
Enabling classes to inherit
Promotes code reuse, establishes
Inheritance properties and methods of
hierarchical relationships
others
Adds flexibility, enables dynamic
Allowing entities to behave
Polymorphism method invocation and common
differently in different contexts
interfaces
Data Encapsulation v/s Data Abstraction
Object Oriented Programming in Java 12
Feature Data Encapsulation Data Abstraction
Bundling data and methods Hiding complex implementation
Definition within a class and restricting details and exposing only essential
access to them functionality
Protects data integrity by Simplifies complex systems by
Purpose controlling access to internal focusing on what the object does
state rather than how
How It’s Using private fields with public Using abstract classes, interfaces,
Achieved getters and setters and abstract methods
Data protection and controlled Simplification and reduction of
Focus
access complexity
Private fields with public Abstract methods in an abstract
Example
methods for access class or interface
Association, Aggregation and Composition in OOP:-
Association
Definition: Association is a general relationship between two independent
objects that enables one object to interact with or use the other. It is the
most basic relationship in OOP.
Characteristics:
Can be one-to-one, one-to-many, many-to-one, or many-to-many.
Indicates that objects are “connected” but maintain their independence.
Example: A Teacher and Student class can be associated since a teacher
teaches multiple students, and students are taught by multiple teachers.
Aggregation
Definition: Aggregation is a special form of association where one class
(the “whole”) contains a reference to another class (the “part”), but both
can exist independently.
Characteristics:
Represents a “has-a” relationship.
Object Oriented Programming in Java 13
The lifespan of the “part” does not depend on the “whole”; they can
exist separately.
Example: A Library and Book class have an aggregation relationship since a
library “has” books, but the book can exist independently of the library.
Composition
Definition: Composition is a stronger form of aggregation where one class
is entirely dependent on another for existence, indicating ownership.
Characteristics:
Represents a “part-of” relationship.
The “part” cannot exist without the “whole”; if the “whole” is destroyed,
the “part” is also destroyed.
Example: A Room and House class have a composition relationship. A room
cannot exist without the house it belongs to.
Differences between Association, Aggregation, and
Composition
Feature Association Aggregation Composition
General “Has-a” relationship; Strong “part-of”
Definition relationship parts can exist relationship; parts
between objects independently depend on the whole
Dependent; part is
Objects are fully Objects can exist
Independence destroyed with the
independent separately
whole
Strength of
Weak Moderate Strong
Bond
Simple association Hollow diamond in
Representation Filled diamond in UML
line UML
Teacher ↔
Example Library ↔ Book House ↔ Room
Student
In summary:
Association indicates a general connection.
Object Oriented Programming in Java 14
Aggregation represents a loose “has-a” relationship with independent
objects.
Composition implies a strong “part-of” relationship where the existence of
one object is tied to the other.
Link and Association
Link and Association are terms related to the relationships between objects in
object-oriented programming:
Link:
A link is a connection between two specific objects. It represents an
instance-level relationship.
For example, if there is a Student object and a Course object, a link exists
if a specific student is enrolled in a specific course.
Association:
Association represents a general relationship between classes rather
than individual objects.
It shows how two classes are conceptually connected, typically using
attributes and methods in one class to reference instances of another.
Associations can have different types:
One-to-One: Each object in one class is associated with one object
in another class.
One-to-Many: An object of one class is associated with multiple
objects of another.
Many-to-Many: Multiple objects in one class can relate to multiple
objects in another.
Example: A Teacher and Student classes may have an association where
teachers teach students, and students are taught by teachers.
Basic Concepts in OOP
Object Oriented Programming in Java 15
public static void main (String[] args)
In Java, the method declaration public static void main (String[] args) serves as
the entry point for any Java application.
1. public
Access Modifier: public means that the main method is accessible from
outside the class, including by the Java Runtime Environment (JRE).
Purpose: Since main is the starting point of execution, it must be accessible
to the JRE, which calls it to start the program.
2. static
Static Keyword: static means that the main method belongs to the class
itself, rather than any specific instance of the class.
Purpose: This allows the JRE to call the main method without needing to
create an instance of the class. Without static , the JRE would have to
instantiate the class before it could call main , which would complicate the
program execution.
3. void
Return Type: void means that main does not return any value.
Purpose: Since the main method is only meant to start the program, there is
no need for it to return any data.
4. main
Method Name: main is a predefined name that the Java compiler and
runtime recognize as the starting point for program execution.
Purpose: The Java specification requires that this method be named main
for it to be recognized as the entry point of the program.
5. String[] args
Parameter: String[] args is an array of String objects, allowing the program
to accept command line arguments.
Purpose: This parameter enables users to pass additional information to the
program at runtime via the command line. Each command-line argument is
passed as a String element in the array args .
Object Oriented Programming in Java 16
Usage Example: If we run java MyClass hello world , args will contain ["hello",
"world"] .
Example of main Method
public class Main {
public static void main (String[] args) {
System.out.println("Hello, World");
if (args.length > 0) {
System.out.println("Arguments provided:");
for (String arg : args) {
System.out.println(arg);
}
} else {
System.out.println("No arguments provided");
}
}
}
Output without Arguments:
>java Main
Hello, World
No arguments provided
Output with Arguments
>java Main Java Programming
Hello, World
Arguments provided:
Java
Programming
Parameter Passing in Programming
Object Oriented Programming in Java 17
Parameter passing refers to the process of providing inputs (arguments) to
functions or methods in programming. When a function or method is called,
parameters are passed to it, allowing it to perform tasks with the provided data.
In most languages, including Java, there are two main ways to pass
parameters:
1. Call by Value: A copy of the actual parameter’s value is passed to the
function.
2. Call by Reference: A reference to the actual parameter (not the value itself)
is passed, meaning that modifications in the function will affect the original
parameter.
Call by Value:-
The function receives a copy of the variable’s value.
Modifications within the function do not affect the original variable.
In Java, primitive types (like int , float , char ) are passed by value.
In this example, the value of num in the main function remains unchanged after
calling the increment method.
public class CallByValueExample {
static void increment (int n) {
n = n + 5; // Modifies only the local copy of n
System.out.println("Inside increment: " + n);
}
public static void main (String[] args) {
int num = 10;
System.out.println("Before calling increment: " + num
increment(num); // Passing the value of num
System.out.println("After calling increment: " + num)
}
}
Output:
Object Oriented Programming in Java 18
Before calling increment: 10
Inside increment: 15
After calling increment: 10
Explanation: num remains 10 in the main method, because only a copy of its
value was passed to the increment function.
Call by Reference:-
The function receives a reference (or address) to the variable.
Modifications within the function affect the original value.
In Java, objects are passed by reference, but the language simulates it as
call by value by passing the object reference value.
In Java, objects are passed by reference, so changes to object attributes inside
a method reflect on the original object outside the method.
class Box {
int height;
Box (int h) {
this.height = h;
}
}
public class CallByReferenceExample {
public static void main (String[] args) {
Box box = new Box(10);
System.out.println("BEfore calling increaseHeight: " +
increaseHeight(box); // Passing the reference of box
System.out.println("After calling inreaseHeight: " +
}
static void increaseHeight (Box b) {
b.height += 5; // Modifies the original object's heig
Object Oriented Programming in Java 19
System.out.println("Inside increaseHeight: " + b.heig
}
}
Output:
Before calling increaseHeight: 10
Inside increaseHeight: 15
After calling increaseheight: 15
Explanation: In this example, box is an object. When increaseHeight is called, it
receives a reference to box . Modifying b.height affects the original box object,
so the change is reflected after the method call.
static Keyword in Java
A static keyword in Java is a modifier that can be applied to variables,
methods, blocks, and nested classes. It indicates that the member it modifies
belongs to the class itself rather than to instances of the class. This means
static members are shared among all instances of the class and can be
accessed without creating an instance of the class.
Static Variables
Declared with the static keyword within a class, static variables are shared
across all instances of that class.
There is only one copy of a static variable, regardless of the number of
instances.
Useful for defining constants or shared properties.
class Example {
static int count = 0; // Shared across all instances
}
Static Methods
Object Oriented Programming in Java 20
Static methods belong to the class rather than an instance and can be
called using the class name (e.g., ClassName.methodName() ).
They cannot access instance (non-static) variables or methods directly, as
they do not operate on specific instances.
Commonly used for utility functions.
class MathUtility {
static int add (int a, int b) {
return a + b;
}
}
class Example {
public static void main (String args[]) {
int r = MathUtility.add(4,5); // Calling the method u
System.out.println(r); // Output: 9
}
}
Static Blocks
A static block is a block of code that gets executed when the class is
loaded, before any objects are created.
Useful for initializing static variables or performing other setup tasks.
class Example {
static int count;
static {
count = 10; // Initialization in a static block
System.out.println("Static block executed");
}
}
Static Nested Classes
Object Oriented Programming in Java 21
Inner classes declared as static can be instantiated without a reference to
an outer class instance.
They do not have access to instance variables or methods of the outer
class.
class Outer {
static class StaticNested {
void display() {
System.out.println("Inside static nested class");
}
}
}
class Example {
public static void main (String args[]) {
Outer.StaticNested nestedInstance = new Outer.StaticNe
nestedInstance.display(); // Output: Inside static ne
}
}
Key Points about static in Java
Memory Efficiency: Static members are loaded once when the class is
loaded, reducing memory overhead.
Access: Static members can be accessed directly using the class name,
without needing an object instance.
Restrictions: Static methods cannot access non-static (instance) members
directly.
Use Case: Commonly used in utility classes, constants and shared
resources.
static v/s final Keyword
1. static :
Object Oriented Programming in Java 22
The static keyword in Java is used to denote that a field, method, or
nested class belongs to the class itself rather than instances of the
class.
Static Fields: A static field is shared across all instances of the class.
Changing it in one instance affects all others.
Static Methods: A static method can be called without creating an
instance of the class and can only access static fields and other static
methods directly.
Example:
class Example {
static int count = 0; // Shared among all instances
static void showCount() {
System.out.println(count);
}
}
2. final :
The final keyword is used to indicate that a variable, method, or class
cannot be modified after it has been set or defined.
Final Variables: A final variable can only be assigned once. If it’s a
primitive type, its value cannot change; if it’s a reference type, the
reference cannot change, but the object’s contents can.
Final Methods: A final method cannot be overwritten by subclasses,
which helps preserve specific behaviors.
Final Classes: A final class cannot be subclassed, preventing any class
from inheriting from it.
Example:
class Example {
final int MAX_COUNT = 100; // Cannot be modified
final void display() {
System.out.println("This method cannot be overri
Object Oriented Programming in Java 23
}
}
Difference:
staticis associated with the class itself, meaning it is shared across all
instances.
final is used to enforce immutability, preventing modification of variables,
methods, or classes.
Message Passing in OOP
Message Passing is a fundamental concept in object-oriented programming
that enables objects to communicate and interact with one another. In simple
terms, it is the process by which one object sends a request (message) to
another object to invoke a method or retrieve a piece of information. This
interaction facilitates the coordination and functionality of objects within a
system.
Key Aspects of Message Passing
1. Method Invocation:
Message passing occurs when an object calls a method of another
object.
The method call acts as a “message” instructing the receiving object to
execute a specific behavior.
2. Encapsulation of Data and Methods:
Since objects encapsulate data and expose only selected methods,
message passing ensures that an object can access another’s
functionality only through these well-defined methods, preserving
encapsulation.
3. Loose Coupling:
Message passing allows objects to interact without knowing the internal
details of each other. This decouples objects, making the system more
flexible and maintainable.
Object Oriented Programming in Java 24
4. Dynamic Interaction:
During runtime, different objects can send messages to each other
depending on program logic, enabling dynamic behavior based in the
context or user input.
Example of Message Passing
In Java, message passing typically happens via method calls.
class Engine {
void start() {
System.out.println("Engine starts");
}
}
class Car {
private Engine engine = new Engine(); // Aggregation (Car
void startCar() {
engine.start(); // Car sends a message to Engine to s
}
}
public class Main {
public static void main (String args[]) {
Car myCar = new Car();
myCar.startCar(); // Car receives a message to start,
}
}
In this example:
The Car object doesn’t access the Engine 's details directly but
communicates by calling engine.start() .
This start() method call is the message sent to the Engine object.
Object Oriented Programming in Java 25
Importance of Message Passing
Promotes Modularity: By interacting through messages, objects maintain
independence, which makes it easier to modify one part of a system
without affecting others.
Supports Polymorphism: Objects can respond differently to the same
message, allowing polymorphic behavior where different classes can
provide their own implementations of a method.
Enables Reusability: Encapsulated, message-driven objects are easier to
reuse in other parts of an application or in different projects.
Method Overloading
Method Overloading is a feature in Java that allows a class to have multiple
methods with the same name but different parameter lists (different types,
number of parameters, or order of parameters). This allows methods to
perform similar functions with varied input.
Purpose: Method Overloading enhances code readability and flexibility, as
methods with the same name can handle different types or number of
inputs.
How it Works: The Java compiler differentiates overloaded methods based
on their parameter lists (not return type). When a method is called, the
compiler matches the arguments with the correct overloaded version of the
method.
Benefits: It improves the clarity of the code and enables better reusability
by allowing related operations to be expressed using the same method
once.
Example:
class MathOperations {
int add (int a, int b) {
return a + b;
}
double add (double a, double b) {
return a + b;
Object Oriented Programming in Java 26
}
int add (int a, int b, int c) {
return a + b + c;
}
}
In this example, the add method is overloaded to handle both integer and
double types, as well as different number of parameters.
Garbage Collection in Java
Garbage Collection in Java is an automatic memory management process that
helps reclaim memory used by objects no longer accessible or in use. This
frees up heap memory space, preventing memory leaks and ensuring efficient
use of system resources.
Purpose: The goal of garbage collection is to identify and discard objects
that are no longer reachable from any references in the program.
How it Works: Java’s garbage collector tracks objects created in the
program. When an object no longer has any references, it becomes eligible
for garbage collection.
Types of Garbage Collectors: Java provides several garbage collectors,
including the Serial, Parallel, CMS (Concurrent Mark-Sweep), and G1
(Garbage First) collectors, which can be selected based on performance
needs.
Benefits: Garbage collection reduces the risk of memory leaks and ensures
efficient memory utilization, which is crucial in long-running applications.
Java’s garbage collection is automatic, but it can be requested manually using
System.gc() , although, it’s not guaranteed to run immediately.
finalize() Method in Java
The finalize() method in Java is a protected method of the Object class that
gets called by the garbage collector before an object is reclaimed.
Object Oriented Programming in Java 27
Purpose: The finalize() method provides a mechanism to perform cleanup
actions, like releasing system resources or closing files, before the object
can be destroyed.
How it Works When the garbage collector determines that there are no
more references to an object, it calls the finalize() method once on that
object (if it exists) before reclaiming the memory. This gives the object a
last opportunity to release resources or perform other cleanup tasks.
Limitations: Since the garbage collector does not guarantee when it will
run, relying on finalize() method for critical cleanup tasks is discouraged.
Starting from Java 9, it is considered deprecated due to its unpredictability,
and alternatives like try-with-resources and finally blocks are recommended
instead.
Example:
class MyClass {
@Override
protected void finalize() {
System.out.println("Cleaning up resources...");
}
}
Inheritance in Java
Types of Inheritance in OOP
In object-oriented programming, inheritance is the mechanism that allows one
class to inherit properties and behaviors (methods and fields) from another
class. This facilitates code reuse, improves organization, and supports
polymorphism. The various types of inheritance are as follows:-
Single Inheritance
Definition: A class inherits from only one superclass. This means each
class has one direct parent.
Object Oriented Programming in Java 28
Purpose: Simplifies the inheritance hierarchy, reduces complexity, and
avoids ambiguity.
Example:
class Animal {
void eat() {
System.out.println("Eating...");
}
}
class Dog extends Animal {
void bark() {
System.out.println("Barking...");
}
}
Here, Dog inherits from Animal , but Animal has no other parent classes.
Multiple Inheritance (Not supported with classes in Java)
Definition: A class inherits from more than one superclass, meaning it has
multiple parents.
Purpose: Allows a class to combine features from multiple parent classes.
Issues: This can lead to the diamond problem, where ambiguity arises if
multiple parents have methods with the same name.
Multilevel Inheritance
Definition: A class inherits from a superclass, which in turn inherits from
another superclass. This creates a chain of inheritance.
Purpose: Establishes a clear hierarchy and enables further specialization in
subclasses.
Example:
class Animal {
void eat() { System.out.println("Eating..."); }
}
Object Oriented Programming in Java 29
class Dog extends Animal {
void bark() { System.out.println("Barking..."); }
}
class Puppy extends Dog {
void weep() { System.out.println("Weeping..."); }
}
Here, Puppy inherits from Dog , and Dog inherits from Animal , creating a
multilevel inheritance chain.
Hierarchical Inheritance
Definition: Multiple classes inherit from a single superclass, making each
subclass independent of the others but sharing a common parent.
Purpose: Allows the sharing of common functionality among multiple
subclasses while keeping them separate.
Example:
class Animal {
void eat() { System.out.println("Eating..."); }
}
class Dog extends Animal {
void bark() { System.out.println("Barking..."); }
}
class Cat extends Animal {
void meow() { System.out.println("Meowing..."); }
}
Here, both Dog and Cat inherit from Animal , making Animal a common parent.
Hybrid Inheritance
Definition: A combination of two or more types of inheritance (e.g.,
hierarchical and multilevel).
Purpose: Allows flexible design by combining multiple inheritance models.
Object Oriented Programming in Java 30
Support in Java: Java does not support hybrid inheritance directly with
classes due to ambiguity issues. However, it can be achieved using a mix of
classes and interfaces.
super Keyword in Java
The super keyword in Java is used within a subclass to refer to its immediate
superclass. It allows access to superclass methods, constructors and
properties, enabling the subclass to inherit and extend the functionality of the
superclass.
1. Accessing Superclass Methods with super
The super keyword can call a methods from the superclass that is
overridden in the subclass. This helps in reusing and extending the
behavior of the superclass method.
class Animal {
void sound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
void sound() {
super.sound(); // Calls Animal's sound method
System.out.println("Dog barking");
}
}
2. Accessing Superclass Constructors with super()
super() is used to call the superclass constructor. If the superclass has a
parameterized constructor, the super() call in the subclass constructor can
pass parameters to it. This is useful for initializing superclass properties
when creating a subclass instance.
The super() call must be the first line in the subclass constructor if used.
Object Oriented Programming in Java 31
class Animal {
Animal (String name) {
System.out.println("Animal's name is: " + name);
}
}
class Dog extends Animal {
Dog (String name) {
super(name); // Calls Animal's constructor with parame
System.out.println(name + " is a dog");
}
}
3. Accessing Superclass Fields with super
The super keyword allows access to fields of the superclass when they are
hidden by fields in the subclass.
class Animal {
String type = "Mammal";
}
class Dog extends Animal {
String type = "Canine";
void printType() {
System.out.println(super.type); // Accesses Animal's
}
}
Key Points about super
Purpose: Enables a subclass to reference its superclass’s members.
Placement: super() must be the first statement in a constructor if used.
Usage: Commonly used to avoid shadowing or overriding issues, and to call
superclass constructors or methods.
Object Oriented Programming in Java 32
Method Overriding
Method overriding is a feature in Java that allows a subclass to provide a
specific implementation of a method that is already defined in its superclass.
This is essential for achieving polymorphism in Java, as it enables a subclass to
offer its own behavior for a method defined by a superclass.
Rules for Overriding:
The method in the subclass must have the same name, return type, and
parameter list as in the superclass.
The access level of the overridden method cannot be more restrictive
than the method in the superclass.
Only inherited methods can be overridden, meaning static , final , and
private methods cannot be overridden.
Purpose: Method overriding allows subclasses to modify the behavior of
inherited methods, providing more specific functionality.
Example:
class Vehicle {
void start () {
System.out.println("Vehicle starts");
}
}
class Car extends Vehicle {
@Override
void start () {
System.out.println("Car starts with key");
}
}
public class Main {
public static void main (String[] args) {
Vehicle myCar = new Car();
myCar.start(); // Output: Car starts with key
Object Oriented Programming in Java 33
}
}
Explanation: The Car class overrides the start method of Vehicle , and
when called, it executes the Car class’s implementation due to dynamic
method dispatch.
Given a method that does not declare any exception, can I
override that method in a subclass to throw an exception?
No, we cannot override a method in a subclass to throw a new or broader
checked exception if the method in the superclass does not declare any
exceptions. This is because Java enforces strict rules around checked
exceptions to ensure that the contract of the superclass method is maintained
in the subclass.
Explanation:-
1. Checked Exceptions: When overriding a method, the subclass method:
Cannot declare any new checked exceptions that were not declared in
the superclass method.
Can only declare the same checked exceptions or a subset (i.e.,
narrower exceptions) of those declared by the superclass method.
If the superclass method does not declare any checked exceptions, then
the overriding method in the subclass also cannot declare any checked
exceptions.
2. Unchecked Exceptions: Unchecked exceptions (subclasses of
RuntimeException ), however, are not subject to these rules. You can declare or
throw unchecked exceptions in the overriding method even if the subclass
method does not declare them.
Example:-
Suppose we have a superclass method that doesn’t declare any exceptions:
class SuperClass {
void display() {
System.out.println("Superclass display method");
Object Oriented Programming in Java 34
}
}
An attempt to override this method in a subclass with a checked exception will
cause a compile-time error:
class SubClass extends SuperClass {
// This will cause a compile-time error
@Override
void display() throws IOException {
System.out.println("Subclass display method");
}
}
However, we can throw an unchecked exception in the overridden method:
class Subclass {
@Override
void display() throws ArithmeticException { // Allowed si
System.out.println("Subclass display method");
throw new ArithmeticException("Unchecked Exception");
}
}
Summary:-
Checked Exceptions: Cannot be newly introduced in the subclass’s
overridden method if they were not declared in the superclass’s method.
Unchecked Exceptions: Can be introduced freely in the subclass’s
overridden method, as they do not need to be declared.
Covariant Return Type
The covariant return type feature in Java allows an overridden method in a
subclass to return a type that is a subclass of the return type declared in the
superclass method. This is useful in object-oriented programming as it allows
for more specific return types in derived classes, improving type safety and
flexibility.
Object Oriented Programming in Java 35
Before Covariant Return Types: Both the superclass and subclass methods
needed to have exactly the same return type.
With Covariant Return Type: The subclass can return a type derived from
the superclass’s return type, as long as it satisfies the requirements of the
superclass’s return type.
Example:
class Animal {
Animal get() {
return this;
}
}
class Dog extends Animal {
@Override
Dog get() { // Covariant return type (returns Dog, subc
return this;
}
}
Explanation: Here, Dog 's overridden get() method returns Dog , a subclass
of Animal , which is permitted due to covariant return types.
Access Modifiers in Java
Access modifiers in Java control the visibility and accessibility of classes,
methods, and variables. The four main access modifiers are public , protected ,
private , and default (no modifier).
1. public
Description: The public modifier allows a class, method, or variable to be
accessible from any other class in any package.
Usage:
Commonly used for methods and constants that need to be accessible
globally.
Object Oriented Programming in Java 36
Classes can also be declared public to be accessible from any other
class.
Example:
public class MyClass {
public int value = 10; //Accessible from any class
public void display() {
System.out.println("Public Method");
}
}
2. protected
Description: The protected modifier allows visibility within the same
package and in subclasses (even if they are in different packages).
Usage: Useful when you want to give access to subclasses but prevent
access from unrelated classes outside the package.
Example:
public class ParentClass {
protected int value = 20; // Accessible within package and
protected void display() {
System.out.println("Protected Method");
}
}
3. private
Description: The private modifier restricts visibility to within the same class
only. It prevents access from any other class, including subclasses and
classes in the same package.
Usage: Commonly used for encapsulating data, like instance variables and
helper methods that should not be accessible from outside the class.
Example:
Object Oriented Programming in Java 37
public class MyClass {
private int value = 20; // Accessible only within MyClass
private void display() {
System.out.println("Private Method");
}
}
4. default (no modifier)
Description: When no access modifier is specified, the default (or
package-private) access level is applied. This means the member is
accessible only within the same package and is not accessible from classes
in other packages.
Usage: Useful for classes, methods, or variables that need to be shared
within a package but should not be accessible from outside the package.
Example:
class MyClass {
int value = 40; // Default access, accessible within the
void display() {
System.out.println("Default Method");
}
}
Summary Table:-
World (Other
Modifier Class Package Subclass
Packages)
public ✅ ✅ ✅ ✅
protected ✅ ✅ ✅ ❌
default ✅ ✅ ❌ ❌
private ✅ ❌ ❌ ❌
Object Oriented Programming in Java 38
Dynamic Method Dispatch:
Dynamic method dispatch, also known as runtime polymorphism, is a process
in Java where the call to an overridden method is resolved at runtime rather
than at compile-time. It allows a superclass reference variable to refer to a
subclass object and call the overridden method in the subclass.
Purpose: It enables Java’s runtime system to decide which method
implementation to execute based on the actual object type, not the
reference type.
How it Works: Java achieves this by looking up the method in the subclass
if a method is overridden. This process enables polymorphic behavior.
Example:
class Animal {
void sound () {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
@Override
void sound () {
System.out.println("Bark");
}
}
public class Main {
public static void main (String[] args) {
Animal myDog = new Dog(); // Upcasting
myDog.sound(); // Output: Bark
}
}
Explanation: Although myDog is declared as Animal , at runtime the Dog class
method is called because of dynamic method dispatch.
Object Oriented Programming in Java 39
Early Binding v/s Late Binding
Features Early Binding Late Binding
The method or function call is
The method or function call is
resolved at runtime. The JVM
resolved at compile time. The
determines the method to execute
Definition compiler determines the method
based on the actual object being
to be executed based on the
referred to, rather than the
type of the reference variable.
reference type.
Static binding, Static linking, Dynamic binding, Run time
Other Names
Compile time polymorphism polymorphism
Happens during compile time,
Happens during runtime, providing
making it faster as there is no
When It Occurs flexibility but adding a slight
runtime overhead for
performance overhead.
determining the method to call.
Used for methods that are
Used for instance methods that
static , final , or private , as
Applicable can be overridden in subclasses
these cannot be overridden.
Scenarios (non-static and non-final
Constructors are also bound
methods).
statically.
Supports runtime polymorphism,
Does not support runtime allowing the JVM to determine
Polymorphism polymorphism since the method which method to call based on the
call is fixed at compile time. actual object type, which enables
more dynamic and flexible code.
Slightly slower due to the runtime
Generally faster because the
decision-making process, but the
Performance method to be called is
difference is usually negligible in
determined at compile time.
practice.
Example:-
Early Binding:
class Example {
static void display() { // Static method - early bin
System.out.println("Static display method");
}
}
class EarlyBinding {
Object Oriented Programming in Java 40
public static void main (String args[]) {
Example.display();
}
}
Late Binding:
class Animal {
void sound() { // Instance method - eligible for lat
System.out.println("Animal sound");
}
}
class Dog extends Animal {
@Override
void sound() { // Overrid3es method in superclass
System.out.println("Bark");
}
}
class LateBinding {
public static void main (String args[]) {
Animal animal = new Dog();
animal.sound(); // resolved at runtime based on
}
}
Abstraction:-
Definition: Abstraction is one of the core principles of Object-Oriented
Programming (OOP), focusing on hiding unnecessary details while
exposing only essential features relevant to the user. It allows developers to
manage complexity by providing a simplified model of the system.
Purpose: The goal of abstraction is to reduce complexity and increase
efficiency by providing only the essential features of an object or process,
Object Oriented Programming in Java 41
hiding internal mechanisms that are not important to the user or external
exam.
How it Works:
In Java, abstraction can be achieved using abstract classes and
interfaces.
Abstract Class: Contains abstract (unimplemented) methods alongside
implemented ones. Abstract classes cannot be instantiated directly;
they are designed to be subclassed.
Interface: Defines a contract for classes without any implementation.
Classes that implement the interface must provide concrete
implementation for its methods.
Example: Consider a vehicle abstract class with an abstract method move() .
Different subclasses like Car , Bike , or Boat would implement move()
differently, while users of these subclasses don’t need to know the exact
implementation.
Advantages of Abstraction:
Enhanced Code Reusability: Abstraction allows for code reuse since
common functionality can be defined in an abstract class or interface.
Improved Maintainability: Reducing visible details means changes to the
implementation do not affect users as long as the interface remains the
same.
Simplification: By presenting only relevant details, abstraction helps
simplify complex systems, making it easier for developers to understand
and work with.
Real-World Analogy: Abstraction is like using a TV remote. You press
buttons to change channels or adjust volume, but you don’t need to know
the internal workings of the remote or TV circuitry to use it effectively.
Levels of Abstraction:
Low-Level Abstraction: Focuses on the internal, detailed working of the
system. Example: bits and bytes in memory management.
High-Level Abstraction: Focuses on essential functionalities without
showing internal details. Example: classes representing complex real-world
Object Oriented Programming in Java 42
objects like a BankAccount or User .
Example Code:
abstract class Vehicle {
abstract void move();
}
class Car extends Vehicle {
void move() {
System.out.println("Car moves on wheels");
}
}
class Boat extends Vehicle {
void move() {
System.out.println("Boat sails on water");
}
}
Applications:
Used in software design to build modular, scalable, and maintainable
applications.
Common in frameworks and APIs, where users interact with higher-level
classes without needing to understand underlying complexities.
In summary, abstraction is a powerful concept in OOP that helps manage
complexity by focusing on essential details and hiding internal workings. It not
only improves the readability and maintainability of code but also allows for
more flexible and scalable system design.
Abstract Class v/s Interface
Object Oriented Programming in Java 43
Feature Abstract Class Interface
Shared base class for related Defines a contract that unrelated
Purpose
classes classes can implement
Can have both abstract and
Method Type Only abstract methods
concrete methods
Can have instance fields of any All fields are public , static ,
Field Type
access level and final by default (constants)
Constructor Can have constructors Cannot have constructors
Inheritance Supports single inheritance only Supports multiple inheritance
Methods and fields can be All methods are public by
Access
public , protected , and default; fields are public static
Modifiers
private . final .
For “is-a” relationships, shared For “can-do” capabilities or
When to Use
state or behavior behavior definitions
Example:
Abstract Class:
abstract class Animal {
String name;
Animal (String name) {
this.name = name;
}
abstract void sound(): // Abstract method
void sleep() { // Concrete method
System.out.println(name + "is sleeping");
}
}
class Dog extends Animal {
Dog (String name) {
super(name);
}
Object Oriented Programming in Java 44
@Override
void sound() {
System.out.println("BarK");
}
}
Interface
interface Flyable {
void fly(); // Abstract method by default
}
class Bird implements Flyable {
public void fly(){
System.out.println("Bird is flying");
}
}
Multiple Inheritance in Java
Java implements multiple inheritance through interfaces rather than classes.
This is because Java does not support multiple inheritance with classes
directly, meaning a class cannot inherit from more than one class to avoid
issues like the diamond problem (ambiguity when a class inherits from two
classes that have methods with the same signature).
Instead, Java allows a class to implement multiple interfaces, which enables it
to inherit from multiple sources of behavior without ambiguity, as interfaces
only define method signatures without actual implementations, or with default
methods.
Example:
interface Printable {
void print(); // Abstract method
}
interface Showable {
Object Oriented Programming in Java 45
void show(); // Abstract method
}
// This class implements both Printable and Showable interface
class Document implements Printable, Showable {
@Override
public void print() {
System.out.println("Printing document...");
}
@Override
public void show() {
System.out.println("Showing document...");
}
}
public class Main {
public static void main (String args[]) {
Document doc = new Document();
doc.print(); // Calls the print method
doc.show(); // Calls the show method
}
}
Explanation:-
1. Interfaces Definition: Printable and Showable are two interfaces with
abstract methods print() and show() .
2. Class Implementation:
The Document class implements both Printable and Showable interfaces.
By doing this, it effectively inherits the behaviors specified by both
interfaces.
The Document class provides concrete implementations of both print()
and show() methods.
3. Calling Methods: In the Main class, we create an instance of Document and
call both print() and show() methods, demonstrating that Document has
inherited behaviors from both Printable and Showable .
Object Oriented Programming in Java 46
Justification:
This approach allows Java to implement a form of multiple inheritance by
combining multiple behaviors from different interfaces. Since interfaces don’t
contain any state or direct implementation (except for default methods), there is
no ambiguity, as the implementing class has to provide concrete behavior or
use default methods from interfaces selectively.
Packages in Java
In Java, a package is a namespace that groups related classes, interfaces, and
sub-packages. Packages help organize code, prevent naming conflicts, and
control access to classes and methods, improving modularity and reusability.
There are two types of packages in java:
1. Built-in Packages: Provided by Java libraries, such as java.util , java.io ,
and java.lang . These contain pre-written classes for common functionalities
(e.g., data structures, input/output operations, and string manipulation).
2. User-defined Packages: Created by developers to organize and group their
own classes logically.
Key Benefits of Using Packages
1. Organizational Structure: Packages organize related classes, making
project easier to navigate and maintain.
2. Avoiding Naming Conflicts: Packages create a separate namespace, so
classes with the same name can exist in different packages without causing
conflicts.
3. Access Control: Classes and methods in a package can be declared with
default (package-private) or protected access, allowing selective exposure
of classes and members to other classes.
4. Code Reusability: Classes grouped in packages can be reused across
multiple projects.
Declaring and Importing Packages
Object Oriented Programming in Java 47
Creating a Package: The package keyword is used to define a package at
the beginning of a Java file.
package com.example.utilities;
public class Utility {
public void display () {
System.out.println("Utility method");
}
}
Importing a Package: Use the import keyword to access classes from other
packages.
import com.example.utilities.Utility;
public class Main {
public static void main (String[] args) {
Utility util = new Utility();
util.display(); // Output: Utility method
}
}
Wildcard Import: import packageName.* imports all classes in a package.
Java’s Package Structure
Java’s standard libraries are organized into packages such as:
java.lang : Fundamental classes like System , String , and Math .
java.util : Collection framework classes like ArrayList , HashMap .
java.io : Classes for input/output operations like File , InputStream , and
OutputStream .
Exception Handling in Java
Object Oriented Programming in Java 48
Exception Handling in java is a powerful mechanism that handles runtime
errors, ensuring that the program does not crash and continues to execute
gracefully. Java provides a structured way to detect, throw, and handle
exceptions, improving program robustness and user experience.
Key Concepts in Exception Handling
1. Exception: An Exception is an event that disrupts the normal flow of the
program. It can be caused by various reasons, such as invalid user input, a
network failure, or file I/O issues.
2. Exception Hierarchy: In Java, exceptions are objects that belong to the
java.lang.Throwable class. The hierarchy includes:
Throwable: The superclass for all error and exception types.
Exception: Represents conditions that a program might want to
catch. It’s further divided into:
Checked Exception: Exceptions that are checked at compile
time, like IOException and SQLException . The compiler ensures that
these exceptions are either handled or declared using throws .
Unchecked Exceptions (Runtime Exceptions): Exceptions that
are not checked at compile time, like NullPointerException and
ArrayIndexOutOFBoundsException . These exceptions usually result
from programming errors and do not require handling.
Error: Represents serious issues that applications typically cannot
handle, such as OutOfMemoryError or StackOverflowError .
Exception Handling Keywords in Java
Java provides five keywords for handling exceptions:
1. try : A block of code that might throw an exception is placed inside the try
block. If an exception occurs, control is transferred to the corresponding
catch block.
2. catch : Used to handle the exception. Each catch block can catch a specific
type of exception. A try block can have multiple catch blocks to handle
different exceptions.
3. finally: A block that always executes, regardless of whether an exception
was thrown or caught. It’s typically used to release resources like files or
Object Oriented Programming in Java 49
database connections.
4. throw : Used to explicitly throw an exception. For instance, throw new
ArithmeticException("Division by zero"); .
5. throws : Used in a method declaration to indicate that a method might throw
certain exceptions. It does not handle the exception itself but lets it
propagate to the caller.
Basic Structure of Exception Handling
try {
// Code that may throw an exception
} catch (ExceptionType1 e) {
// Handle ExceptionType1
} catch (ExceptionType2 e) {
// Handle ExceptionType2
} finally {
// Code that will always execute
}
Example of Exception Handling
public class ExceptionExample {
public static void main (String[] args) {
try {
int[] numbers = {1,2,3};
System.out.println(numbers[5]); // Throws ArrayInd
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception caught: " + e);
} finally {
System.out.println("Finally block executed");
}
}
}
Output:
Object Oriented Programming in Java 50
Exception caught: java.lang.ArrayIndexOutOfBoundsException: 5
Finally block executed
Types of Exceptions
Checked Exceptions
These are exceptions that the compiler checks during compilation, requiring
them to be either handled with try-catch or declared in the method signature
with throws .
Examples: IOException , SQLException .
Example:
public void readFile() throws IOException {
FileReader file = new FileReader("file.txt");
file.read();
}
Unchecked Exceptions (Runtime Exceptions)
These exceptions are not checked at compile time but occur during execution.
They often result from programming errors, such as null references or illegal
array indexing.
Examples: NullPointerException , ArithmeticException .
Example:
int result = 10 / 0; // Throws ArithmeticException
Errors
Errors are serious issues beyond the application’s control. They are not meant
to be caught or handled by programs.
Examples: OutOfMemoryError , StackOverflowError .
Advantages of Exception Handling
Object Oriented Programming in Java 51
1. Separation of Error-Handling Code: By using try-catch , the error-handling
code is separated from regular logic, making the program easier to read
and maintain.
2. Improves Program Reliability: Properly handled exceptions allow programs
to continue running, providing better resilience and a smoother user
experience.
3. Promotes Cleaner Code: Using exceptions encourages developers to write
cleaner code, ensuring that potential issues are handled appropriately.
4. Simplifies Debugging: Exception stack traces make it easier to identify and
debug the exact location of errors.
Custom Exceptions
Java allows developers to create their own custom exceptions by extending the
Exception class. This is useful when the application has unique conditions that
aren’t covered by built-in exceptions.
class CustomException extends Exception {
public CustomException (String message) {
super(message);
}
}
public class CustomExceptionDemo {
public static void main (String[] args) {
try {
throw new CustomException("This is a custom excep
} catch (CustomException e) {
System.out.println("Caught: " + e.getMessage());
}
}
}
Output:
Caught: This is a custom exception
Object Oriented Programming in Java 52
Best Practices in Exception Handling
1. Catch Specific Exceptions: Catch specific exceptions rather than general
ones like Exception or Throwable for better error handling and debugging.
2. Use Finally to Clean Up Resources: Always close resources like files and
database connections in the finally block or use try-with-resources .
3. Avoid Swallowing Exceptions: Never catch an exception without handling it
or logging it, as this can hide problems in the code.
4. Use Custom Exceptions Judiciously: Create custom exceptions when
meaningful to the application and add information specific to the
application’s domain.
Chained Exceptions in Java
Chained Exceptions in Java allow an exception to contain another exception,
which is helpful in preserving the original cause of an error when an exception
triggers another exception. This feature helps developers track the sequence of
exceptions that led to an error, providing more detailed and meaningful errors
for debugging and logging.
Java introduced chained exceptions in JDK 1.4, using two main methods in the
Throwable class:
1. initCause (Throwable cause) : Initializes the cause of the exception.
2. getCause() : Retrieves the underlying exception (cause) that triggered the
current exception.
Purpose of Chained Exceptions
Chained exceptions are particularly useful in cases where:
A low-level exception (e.g., IOException ) triggers a higher-level exception
(e.g., CustomException ).
A method that catches an exception wants to throw a different exception
but also preserve the original cause.
Syntax Example
Object Oriented Programming in Java 53
public class ChainedExceptionDemo {
public static void main(String[] args) {
try {
try {
// Low-level exception
throw new ArithmeticException("Division by ze
} catch {
// Wrapping the exception into a higher-level
throw new Exception("Higher-level exception",
}
} catch (Exception e) {
// Displaying both exceptions in the chain
System.out.println("Caught: " + e);
System.out.println("Caused by: " + e.getCause());
}
}
}
Output:
Caught: java.lang.Exception: Higher-level exception
Caused by: java.lang.ArithmeticException: Division by zero
Benefits of Chained Exceptions
1. Enhanced Debugging: They provide a complete chain of events, making it
easier to track the root cause.
2. Improved Readability: A clear stack trace that includes the underlying
cause helps developers quickly understand and resolve issues.
3. Error Wrapping: Allows wrapping lower-level exceptions with higher-level
exceptions to provide more meaningful context without loosing the original
error details.
Threading in Java
Object Oriented Programming in Java 54
Threading in Java is a process that enables concurrent execution of two or
more parts of a program for maximum utilization of CPU resources. Java
provides built-in support for multithreading through the java.lang.Thread class
and the java.lang.Runnable interface, allowing programs to perform multiple tasks
simultaneously.
Key Concepts in Threading
1. Thread: A thread is the smallest unit of a process. A single Java application
can have multiple threads running concurrently.
2. Multithreading: The process of executing multiple threads simultaneously.
Each thread runs independently and can perform a separate task.
3. Concurrency: The ability to execute multiple tasks at the same time.
Multithreading is one way to achieve concurrency in Java.
Process v/s Thread
Feature Process Thread
A thread is a lightweight unit of a
A process is an independent
process, sharing memory and
Definition program in execution with its
resources with other threads in
own memory space.
the same process.
Memory Each process has a separate Threads share the memory and
Allocation memory space. resources of the parent process.
Requires complex Threads can communicate
Inter-Process
mechanisms like pipes, directly since they share the same
Communication
sockets, or shared memory. memory space.
Processes have a higher
Threads have lower overhead as
overhead due to their
Overhead they share resources and
independent memory and
memory.
resource management.
Creation Time Slower to create and initialize. Faster to create and initialize.
If one process crashes, it If one thread crashes, it may
Crash Impact generally doesn’t affect other affect the entire process,
processes. including other threads.
Each thread instance in Java
Each Java application runs as
Example in Java represents a separate thread
a separate process in the OS.
within the Java process.
Object Oriented Programming in Java 55
Multiprocessing v/s Multithreading
Feature Multiprocessing Multithreading
Uses multiple processors or Uses multiple threads within a
Definition CPU cores to execute multiple single process to execute tasks
processes simultaneously. concurrently.
Each process has its own Threads share the same
Memory Usage memory space, so more memory within the process, so
memory is used. memory usage is lower.
Context switching between
processes is slower as each Context switching is faster due
Context Switching
process has its own memory to shared memory.
and resources.
Inter- Complex communication Easier and faster communication
Process/Thread mechanisms (e.g., shared as threads share the same
Communication memory, message passing). memory space.
Limited scalability since all
Better scalability on systems threads are part of a single
Scalability with multiple processors or process and limited by the
cores. process’s memory and
resources.
Limited parallelism; multiple
Achieves true parallelism as
threads may not fully utilize
Parallelism processes can run on separate
multi-core CPUs as effectively
CPUs/cores.
as processes.
Multiple threads within a single
Running multiple applications
Example Java application handling
simultaneously on an OS.
different tasks concurrently.
Creating Threads in Java
Java provides two primary ways to create a thread:
1. Extending the thread Class
2. Implementing the Runnable Interface
1. Extending the Thread Class
In this method, a class extends the Thread class and overrides its run() method
to define the thread’s task.
Object Oriented Programming in Java 56
Example:
class MyThread extends Thread {
public void run () {
for (int i=0; i<5; i++) {
System.out.println("Thread: " + i);
try {
Thread.sleep(500); // Sleep for 500 ms
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
}
public class ThreadExample {
public static void main (String[] args) {
MyThread t1 = new MyThread();
t1.start(); // Starts the thread
}
}
Explanation:
The MyThread class extends Thread and overrides the run() method, which
specifies the code to be executed by the thread.
The start() method begins the execution of the thread and calls run()
internally.
2. Implementing the Runnable Interface
This method involves implementing the Runnable interface and passing an
instance of the implementing class to a Thread object.
Example:
class MyRunnable implements Runnable {
public void run () {
for (int i=0; i<5; i++) {
System.out.println("Runnable: " + i);
Object Oriented Programming in Java 57
try {
Thread.sleep(500);
} catch {
System.out.println(e);
}
}
}
}
public class RunnableExample {
public static void main (String[] args) {
MyRunnable myRunnable = new MyRunnable(); // Creating
Thread t1 = new Thread(myRunnable);
t1.start();
}
}
Explanation:
MyRunnable implements Runnable and overrides the run() method.
t1.start() initiates the thread, which runs the run() method.
Thread Life Cycle
1. New: A thread is in the new state after its creation, but before calling
start() .
2. Active: After calling start() , the thread enters the active state. Contains
two states within it:
a. Runnable: A thread, that is ready to run is then moved to the runnable
state.
b. Running: When the thread gets the CPU, it moves from the runnable to
the running state.
3. Blocked/ Waiting: A thread enters this state when waiting for resources or
another thread.
4. Timed Waiting: A thread can be in a timed waiting state using sleep() or
wait(long timeout) .
Object Oriented Programming in Java 58
5. Terminated: A thread reaches this state once it completes execution or is
terminated.
Important Methods in Threading
1. start() : Starts the execution of the thread by calling run() .
2. run() : Contains the code that defines the thread’s task.
3. sleep(long milliseconds) : Makes the thread pause execution for a specified
time.
4. join() : Waits for a thread to die before executing further code.
5. yield() : Pauses the currently executing thread to allow other threads to run.
6. interrupt() : Interrupts a thread that may be in a waiting or sleeping state.
Thread Synchronization
Synchronization is essential when multiple threads access shared resources,
to prevent data inconsistency. Java provides synchronized methods and blocks
to achieve this.
Example:
class Counter {
private int count = 0;
public synchronized void increment() {
Object Oriented Programming in Java 59
count++;
}
public int getCount() {
return count;
}
}
public class SyncExample {
public static void main (String[] args) throws Interrupted
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i=0; i<1000; i++)
counter.increment();
});
Thread t2 = new Thread(() -> {
for (int i=0; i<1000; i++)
counter.increment();
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Count: " + counter.getCount());
}
}
Explanation:
increment() is synchronized, ensuring that only one thread can modify count
at a time.
t1.join()and t2.join() ensure that the main thread waits until both threads
complete execution.
Object Oriented Programming in Java 60
Inter-Thread Communication
Java allows threads to communicate and coordinate through wait() , notify() ,
and notifyAll() methods. These methods must be called within a synchronized
context.
Example:
class SharedResource {
private int data;
private boolean available = false;
public synchronized void produce (int value) throws Inter
while (available) {
wait(); // Wait if data is available
}
data = value;
available = true;
notify(); // Notify waiting consumer
}
public synchronized int consume () throws InterruptedExce
while (!available) {
wait(); // Wait if no data is available
}
available = false;
notify(); // Notify waiting producer
return data;
}
}
public class ProducerConsumerExample {
public static void main (String[] args) {
SharedResource resource = new SharedResource();
Thread producer = new Thread(() -> {
try {
for (int i=1; i<=5; i++) {
resource.produce(i);
Object Oriented Programming in Java 61
System.out.println("Produced: " + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread consumer = new Thread(() -> {
try {
for (int i=1; i<=5; i++) {
int value = resource.consume();
System.out.println("Consumed: " + value);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
}
}
Explanation:
Producer generates data and calls produce() , which stores data and notifies
the consumer.
Consumer waits for data using consume() , retrieves it, and notifies the
producer.
Deadlock
A deadlock occurs when two or more threads are waiting for each other to
release resources, causing them to be stuck indefinitely.
Example:
Object Oriented Programming in Java 62
public class DeadlockExample {
static final Object lock1 = new Object();
static final Object lock2 = new Object();
public static void main (String[] args) {
Thread t1 = new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread 1: Holding lock1..
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
synchronized (lock2) {
System.out.println("Thread 1: Holding loc
}
}
});
Thread t2 = new Thread(() -> {
synchronized (lock2) {
System.out.println("Thread 2: Holding lock2..
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
synchronized (lock1) {
System.out.println("Thread 2: Holding loc
}
}
});
t1.start();
t2.start();
}
}
In this example, t1 and t2 each acquire a lock and wait for the other, causing
a deadlock.
Object Oriented Programming in Java 63