0% found this document useful (0 votes)
3 views214 pages

Java Notes Professional

The document is a comprehensive study guide on Java, covering its history, foundational concepts, data types, variables, and program structure. It explains the 'Write Once, Run Anywhere' philosophy, the roles of JVM, JRE, and JDK, as well as the differences between primitive and non-primitive data types. Additionally, it provides insights into Java file organization, package usage, and the execution flow of Java programs.

Uploaded by

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

Java Notes Professional

The document is a comprehensive study guide on Java, covering its history, foundational concepts, data types, variables, and program structure. It explains the 'Write Once, Run Anywhere' philosophy, the roles of JVM, JRE, and JDK, as well as the differences between primitive and non-primitive data types. Additionally, it provides insights into Java file organization, package usage, and the execution flow of Java programs.

Uploaded by

sandeep
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Java Complete Study Notes | By Jatin Sir

JAVA
Complete Study Notes
From Basics to Advanced — A Structured Reference Guide

By Jatin Sir
Professionally Formatted Edition

Page 1 of 214
Java Complete Study Notes | By Jatin Sir

Page 2 of 214
Java Complete Study Notes | By Jatin Sir

Chapter 1: Java's Story & Foundations


History, WORA Philosophy, JVM/JRE/JDK

01_Java’s_Story :
Java's Story :

"Write Once, Run Anywhere” (WORA) - The promise that made Java a legend!
Java's official slogan - introduced by Sun Microsystems when Java was launched in the
mid-1990s.
What it means?
We can write Java code on one platform (say, Windows), compile it to bytecode, and then run it
anywhere — Linux, macOS, embedded systems — as long as a
Java Virtual Machine (JVM) exists there.
We don’t need to rewrite our code for each OS.
Facts:
Created by James Gosling at Sun Microsystems in 1995.
Originally called Oak, renamed to Java (inspired by coffee!)
Platform-independent thanks to the JVM (Java Virtual Machine)
Runs billions of devices — from Android apps to ATMs!
Major Java Version Highlights!
| Version
| Year
| Major Highlights
| Java 10–14. | 2018–2020 | var keyword, Switch Expressions, Text Blocks
JAVA'S main components !
| Component | Role
JVM - Java Virtual Machine
• Runs the compiled .class bytecode.
• Converts bytecode to machine code line by line.
• Part of JRE.
JRE - Java Runtime Environment
• JRE + development tools (javac, debugger, etc).
• Used to write and compile Java programs.
Java Execution Flow !
[Link]("Hi, I'm Java!");
What is a Data Type?
A data type defines HOW MUCH MEMORY is required to store data and what kind of data a
variable can hold — such as numbers, characters, or logical values.

Page 3 of 214
Java Complete Study Notes | By Jatin Sir

How Computers Store Data ?


Computers can’t directly store decimal numbers like 0 to 9 — they only understand binary (0s
and 1s).
So, whenever we store a value like 15, the computer automatically converts it to binary, e.g., 15
• 1111.
This binary data is then stored using transistors — tiny electronic switches that represent:
0 → OFF state
1 → ON state
Each 0 or 1 is called a bit (short for binary digit), and it's the smallest unit of data in computing.
Bit, Nibble, Byte Breakdown
Data Types in Java
Java has two categoriesS of data types:
| Type
| Details
Java Primitive Data Types
Java provides 8 primitive types.
PRIMITIVES store ACTUAL VALUE directly in memory.
TAKEAWAY
Primitive local variables do NOT get default values.
Default values are automatically assigned only to instance and static variables.
Non-Primitive Data Types
Non-primitive types STORE MEMORY ADDRESS (references), not actual values. They point
to OBJECTS stored in the HEAP MEMORY.
These include:
• Classes
• Arrays
• Interfaces
• Strings
• Enums
Example
int age = 30;
float pi = 3.14f;
char grade = 'A';
boolean isPassed = true;
## Notes
• Use int by default for whole numbers and double for decimal numbers.
• Use float only when memory is a concern and precision is less important.
• char is used to store a single character (in Unicode).
• boolean is not numeric — it stores logical values (true or false).

Page 4 of 214
Java Complete Study Notes | By Jatin Sir

Data Types - Practice


1. What are the 8 primitive data types in Java?
• byte, short, int, long, float, double, char, boolean
2. Why does Java use fixed sizes for its data types?
• To maintain platform independence and consistency across different machines .
3. What is the default value of char and boolean?
• char- '\u0000' (null character); boolean- false
4 .What is the size of boolean in Java?
• Java doesn't define a specific bit size for boolean, but logically it's 1 bit. Actual memory
used depends on JVM.
5. Can we store a char in an int variable?
• Yes, because char is internally stored as a Unicode integer value (2 bytes). Implicit casting
is allowed.
[Link] is the difference between float and double?
• float is 32-bit and less precise (6–7 decimal digits), double is 64-bit and more precise (15
digits). Use float when memory is a constraint.
7. What happens if you assign a float to an int?
• Compilation error: “possible lossy conversion”. You must explicitly cast it: int x = (int)
3.14;
8. What is type casting?
• Changing one data type to another. Implicit (widening) and explicit (narrowing) casting.
10. Why is char 2 bytes in Java?

Page 5 of 214
Java Complete Study Notes | By Jatin Sir

Chapter 2: Data Types & Variables


Primitive and Non-Primitive Types, Memory Allocation

11. What is the range of int in Java?


• -2,147,483,648 to 2,147,483,647 (-2^31 to 2^31 - 1). Exceeding it causes overflow.
12. What is the difference between null, 0, and false?
null: reference to nothing (objects)
0: numeric zero (int/float)
false: boolean value.
Variables
What is a Variable?
A variable is a name given to a memory location. It is used to store data that can be changed
during the execution of a program.
Syntax >> datatype variableName = value;
int a = 10;
+-------------+
+-------------+
| Code
| Meaning
int → Data type
a → Variable name
10 → Value assigned
Memory is allocated based on the data type (int gets 4 bytes)
Points to Remember
Variables focus on memory allocation.
The data type determines how much memory is required and what type of value the variable can
store.
Variables allow us to access and manipulate stored data by referring to the variable name, not the
memory address.
Key TakeAways:
What happens when you declare a variable?
The compiler reserves memory in RAM to hold a value of the specified data type.
The variable name acts like a label pointing to that memory location.
int age = 25; // Declaration
Variable
+-----------+
| age = 25
+-----------+

Page 6 of 214
Java Complete Study Notes | By Jatin Sir

Memory (4 bytes)
int tells Java to reserve 4 bytes in RAM.
The value 25 will be stored in that 4-byte memory block.
The variable name age acts as a pointer to the reserved memory where the data (like 25) is kept.
04_Literals
What is a Literal?
A literal is a constant value written directly in the code.
It represents a fixed value assigned to a variable.
Notes
Literals are used with primitive data types like int, float, char, boolean.
null is used with non-primitive types (like objects or Strings).
Each literal tells the compiler what kind of value is being assigned.
Example in Code:
int score = 88;

// Integer Literal

float pi = 3.14f;

// Floating Point Literal

char grade = 'A';

// Character Literal

String name = "John";

// String Literal

boolean isPassed = true; // Boolean Literal


String city = null;

// Null Literal

Writing the First Code


Where Do Java Files Go - Java Source File Location :
• All Java source files are typically stored inside a src (source) folder.
• Java source files use the .java extension.
• It's best practice to organize source files using PACKAGES.
src

Page 7 of 214
Java Complete Study Notes | By Jatin Sir

└── javaprograms
└── [Link]
• A PACKAGE in Java is like a FOLDER on our computer.
Just like a folder can contain many files, a package can contain many Java classes (files).
• Helps in:
• Organizing code
• Avoiding name conflicts
• Controlling access
Syntax to declare a package - package javaprograms
package is a RESERVED KEYWORD in Java.
Package names should be written in LOWER CASE by convention.
Java Program Structure
A basic Java class looks like this:
public class Example {
public static void main(String[] args) {

// Code block starts

// logic here

// Code block ends

}
}
Understanding the Block Structure
Class starts here
public class HelloWorld {
public static void main(String[] args) {
[Link]("Hello, Java!");
} // Main method ends here
} // Class ends here
Can We Create a private Class?
In Java:

// Main method starts here

Why multiple public classes not allowed in java?


Entry Point Clarity

Page 8 of 214
Java Complete Study Notes | By Jatin Sir

// File name: [Link]

public class A {
}
public class B {

// Compilation error: Only one public class is allowed

}
Summary
Place .java files under src/package_name/.
Always start the file with a package declaration (unless in the default package).
Only one public top-level class is allowed per .java file.
Class name must match the filename when using public.
Q: Why does Java allow only one public class per .java file? What happens if we try to define
two public classes in the same file?
Java enforces a one-to-one relationship between the public class and the file name for clarity,
maintainability, and proper class loading by the JVM.
• If two public classes are defined in the same .java file, the compiler will throw an error: The
public type X must be defined in its own file.
• Only one class can be public, and its name must match the file name.
Understanding Code Execution
Step-by-Step Breakdown of Java Code
Line 1: package example1;

// package name

Line 2: public class Example1 {

// class opening brace

Line 3:
public static void main(String[] args) { // main method opening brace
Line 4:
method
int a = 20;
Line 5:
long g = 2000;

Page 9 of 214
Java Complete Study Notes | By Jatin Sir

Line 6:
char gender = 'm';
Line 7:
float percentage = 33.23f;
Line 8:
boolean isPercentage = false;
Line 9:
[Link](a);
Line 10:
Line 11: }
}

// local variables as they are: Declared inside the main()

// main method closing brace

// class closing brace

Line-by-Line Execution:
Line 1: package Example1;
Declares that this class belongs to the example1 package, which helps organize related Java
files together in a structured way (like folders).

Page 10 of 214
Java Complete Study Notes | By Jatin Sir

Chapter 3: Literals & Java Program Structure


Literals, Packages, Code Execution Flow

| age = 25
+-----------+
Memory (4 bytes)
int tells Java to reserve 4 bytes in RAM.
The value 25 will be stored in that 4-byte memory block.
The variable name age acts as a pointer to the reserved memory where the data (like 25) is kept.
04_Literals
What is a Literal?
A literal is a constant value written directly in the code.
It represents a fixed value assigned to a variable.
Notes
Literals are used with primitive data types like int, float, char, boolean.
null is used with non-primitive types (like objects or Strings).
Each literal tells the compiler what kind of value is being assigned.
Example in Code:
int score = 88;

// Integer Literal

float pi = 3.14f;

// Floating Point Literal

char grade = 'A';

// Character Literal

String name = "John";

// String Literal

boolean isPassed = true; // Boolean Literal


String city = null;

// Null Literal

Page 11 of 214
Java Complete Study Notes | By Jatin Sir

Writing the First Code


Where Do Java Files Go - Java Source File Location :
• All Java source files are typically stored inside a src (source) folder.
• Java source files use the .java extension.
• It's best practice to organize source files using PACKAGES.
src
└── javaprograms
└── [Link]
• A PACKAGE in Java is like a FOLDER on our computer.
Just like a folder can contain many files, a package can contain many Java classes (files).
• Helps in:
• Organizing code
• Avoiding name conflicts
• Controlling access
Syntax to declare a package - package javaprograms
package is a RESERVED KEYWORD in Java.
Package names should be written in LOWER CASE by convention.
Java Program Structure
A basic Java class looks like this:
public class Example {
public static void main(String[] args) {

// Code block starts

// logic here

// Code block ends

}
}
Understanding the Block Structure
Class starts here
public class HelloWorld {
public static void main(String[] args) {
[Link]("Hello, Java!");
} // Main method ends here
} // Class ends here
Can We Create a private Class?

Page 12 of 214
Java Complete Study Notes | By Jatin Sir

In Java:

// Main method starts here

Why multiple public classes not allowed in java?


Entry Point Clarity

// File name: [Link]

public class A {
}
public class B {

// Compilation error: Only one public class is allowed

}
Summary
Place .java files under src/package_name/.
Always start the file with a package declaration (unless in the default package).
Only one public top-level class is allowed per .java file.
Class name must match the filename when using public.
Q: Why does Java allow only one public class per .java file? What happens if we try to define
two public classes in the same file?
Java enforces a one-to-one relationship between the public class and the file name for clarity,
maintainability, and proper class loading by the JVM.
• If two public classes are defined in the same .java file, the compiler will throw an error: The
public type X must be defined in its own file.
• Only one class can be public, and its name must match the file name.
Understanding Code Execution
Step-by-Step Breakdown of Java Code
Line 1: package example1;

// package name

Line 2: public class Example1 {

// class opening brace

Line 3:
public static void main(String[] args) { // main method opening brace

Page 13 of 214
Java Complete Study Notes | By Jatin Sir

Line 4:
method
int a = 20;
Line 5:
long g = 2000;
Line 6:
char gender = 'm';
Line 7:
float percentage = 33.23f;
Line 8:
boolean isPercentage = false;
Line 9:
[Link](a);
Line 10:
Line 11: }
}

// local variables as they are: Declared inside the main()

// main method closing brace

// class closing brace

Line-by-Line Execution:
Line 1: package Example1;
Declares that this class belongs to the example1 package, which helps organize related Java
files together in a structured way (like folders).
Package names should always be in lowercase — this is a Java naming convention to avoid
conflicts and keep things consistent.
Line 2: public class Example1 {
Defines a Java class named Example1.
The keyword CLASS tells the compiler this is a class definition.
Line 3: public static void main(String[] args) {
This is the starting point of the program.
Java execution begins with the main() method.
• main() must be PUBLIC STATIC or JVM won't start execution.

Page 14 of 214
Java Complete Study Notes | By Jatin Sir

public: So that JVM can access it from anywhere.



static: So JVM can run the method without creating an object.

void: It doesn’t return any value.

Java only executes methods, not entire classes directly.
Execution happens inside STACK MEMORY, which is a LIFO (Last In First Out) data structure
— the most efficient memory area in the Java for method execution.
A data structure defines how data is organized and stored in memory so it can be accessed
and managed efficiently.
Line 4: int a = 20; // Initialization
“a” is a variable declared inside the method – so it is called Local Variable.
20 is stored inside a.
Since 20 is declared inside a method, it's stored in the stack memory.
Line 5: long g = 2000;
Java checks the right-hand side first .

2000 is an integer literal, and by default, Java treats it as int. (Any whole number written
without a suffix (L, f, etc.) is considered as an integer literal )

long g = 2000; → Java sees that g is of type long.

Since int can safely fit into long, Java automatically promotes (aka widens) 2000 to
2000L behind the scenes.

This process is called widening primitive conversion, also known as **implicit type
casting, where Java automatically converts a smaller data type into a larger one**.

Like a, g is also a local variable and goes into the stack.
Line 6: char gender = 'm';
A character value 'm' is assigned to variable gender. Stored in stack memory.
Line 7: float percentage = 33.23f;
Stores a floating-point number in variable percentage.
📌 Note: Note: The **f** is necessary to explicitly mark it as a float.
How the Stack Memory Looks Internally ?

Stack Memory

Page 15 of 214
Java Complete Study Notes | By Jatin Sir

+---------------------------+
|

main()

Top <----------------------+

| +---------------------+ |

| | isPercentage: false | |

| | percentage: 33.23f | |

| | gender: 'm'

| |

| | g: 2000L

| |

| | a: 20

| |

| +---------------------+ |

Page 16 of 214
Java Complete Study Notes | By Jatin Sir

+---------------------------+

The **'top of the stack'** specifically points to the **current method* being executed.

Once the main() method finishes execution, all local variables that were pushed onto the
stack
are popped out — clearing the stack memory and making room for the next method call.
Line 8: boolean isPercentage = false;
A boolean variable stores either true or false.
Stored in the stack like the others.
Line 9: [Link](a);
Prints the value of variable a to the console.

**System** is a predefined class in Java.

out is a reference to the output stream (usually the screen).

**println()** is a method that prints the value passed to it.

Line 10: } // main method closing brace

This marks the **end of the main() method**.

When the method ends, all the local variables created inside the stack are removed and
stack is
cleared, and he program ends.
Line 11: } // class closing brace

Page 17 of 214
Java Complete Study Notes | By Jatin Sir

Ends the Example1 class definition.

Local Variables and Default Values

In Java, local variables (declared inside methods) are not automatically initialized.

If we write: int a; // declared but not initialized

[Link](a); // Error: variable a might have not been initialized.

We’ll get a compile-time error. Why?

Because the compiler can't guarantee what value a hold — it could be garbage or random —
and
Java wants to avoid unsafe behavior.

Page 18 of 214
Java Complete Study Notes | By Jatin Sir

Chapter 4: Conditional Statements


if, if-else, if-else-if Ladder, Switch Statement

If we write: int a; // declared but not initialized


[Link](a); // Error: variable a might have not been initialized.
We’ll get a compile-time error. Why?
Because the compiler can't guarantee what value a hold — it could be garbage or random — and
Java wants to avoid unsafe behavior.
Key Concepts:

Local Variables: Variables declared inside a method — like a, g, gender, etc. — are local
and live temporarily in the stack during method execution.

Java does not automatically initialize local variables with default values — if we declare
them without assigning, they hold garbage values.

Once main() completes, all the values are removed from stack memory.
Conditional Statements
Java executes code sequentially, line by line.
But if, we want to control the flow based on certain conditions — that’s where conditional
statements help.
Conditional statements in Java:
if
if-else
if-else-if
switch
1. if Statement

// Syntax

if (condition) {
block of code to execute if condition is true
}
How does it works ?
If the condition is true, Java executes the immediate next statement or code block.
If the condition is false, Java skips the next statement/block.
Example 1: Single Statement
int c = 100;

Page 19 of 214
Java Complete Study Notes | By Jatin Sir

if (c > 50)
[Link]("C is greater than 50");
Example 2: Code Block with Multiple Lines
if (c > 5) {
[Link]("Hello");
[Link]("How are you");
[Link]("Are you learning java");
}
Example 3: False condition without braces
int c = 10 + 5;
if (c > 10) // False
[Link]("C is lesser than 10"); // skipped
[Link]("C is greater than 10"); // This is outside the if - always executed
Java's Rule for if Without Braces {}
When we write an if statement without {}, only the immediate next line (the first one) is treated
as part of the if.

Example 4: Using & (bitwise AND) with


two conditions
int a = 100;
int b = 20;
if (a > b && b > a) {
[Link]("a is greater than b");
conditions are true!

// Code block will only be excecuted, if both

[Link]("b is greater than a");


}
Condition Analysis:
a > b → 100 > 20 → true
b > a → 20 > 100 → false
true && false → false
Notes
Always use curly braces {} if the if block has more than one line.
If the block isn’t executed (condition is false), it becomes a dead code block.
if Block Execution
if (c > 10)
True

Page 20 of 214
Java Complete Study Notes | By Jatin Sir


Execute next statement(s)
if (c > 10)
False

Skip the next statement(s)
2. if else
The if-else statement lets you choose between two blocks of code based on whether the
condition is true or false**
Syntax :
if (condition) {

// executes if condition is true

} else {

// executes if condition is false

}
Example:
int a = 10;
int b = 20;
if (a > b) {
[Link]("a is greater");
} else {
[Link]("b is greater");
}
Output:
Since a > b is false, the output will be: b is greater
Key Concept:
The if block runs if the condition is true
The else block runs if the condition is false
Only one of the two blocks will execute
Tip
Used when you have exactly two outcomes.
Avoid using else without if — they always work as a pair
3. if-else-if Ladder
The if-else-if ladder is used when you need to check multiple conditions (sequential checks),
one after another.

Page 21 of 214
Java Complete Study Notes | By Jatin Sir

It allows you to choose one block out of many based on which condition is true first.
Syntax:
if (condition1) {

// runs if condition1 is true

} else if (condition2) {

// runs if condition2 is true

} else if (condition3) {

// runs if condition3 is true

} else {

// runs if none of the above are true

}
Example
int percentage = 75;
if (percentage > 100 || percentage < 0) {

// Boundary Condition Check

[Link]("Invalid Percentage"); // >100 or <0 is invalid


return; // Stops execution if value is invalid
}
if (percentage > 90) {

// Grade Assignment Based on Valid Percentage

grade = 'A';
} else if (percentage >= 80 && percentage < 90) {
grade = 'B';
} else if (percentage >= 70 && percentage < 80) {
grade = 'C';
} else if (percentage < 70) {
grade = 'F'; // Handles rest of values <70
} else {

Page 22 of 214
Java Complete Study Notes | By Jatin Sir

grade = '-'; // Missing value case (if percentage is 0 for example)


}
[Link]("Grade: " + grade);
[Link] Statement
A switch statement is used when we have multiple fixed values to compare against one
variable.**
switch (expression) {
case value1:

// code block

break;
case value2:

// code block

break;

// ... more cases

default:

// default block (optional)

}
Key Points
switch
Starts the block that checks different values
case
Each possible value to match
break
Exits the switch after a match is found
default
(Optional) Runs if no case matches
Example: Switch Based on Grade
char grade = 'B';
switch (grade) {
case 'A':

Page 23 of 214
Java Complete Study Notes | By Jatin Sir

Chapter 5: Loops
for, while, do-while, Enhanced For Loop

[Link]("Excellent!");
break;
case 'B':
[Link]("Very Good!");
break;
case 'C':
[Link]("Good");
break;
case 'D':
[Link]("You passed");
break;
case 'F':
[Link]("Better luck next time");
break;
default:
[Link]("Invalid grade");
}
How It Works?
If grade = 'B'?
Java checks:
(1) Is it 'A'? No
(2) Is it 'B'? Yes → prints "Very Good!" and exits
Note
Works with byte, short, int, char, String, and enums (not float, double).
Without break, all below cases will execute ("fall-through").
Loops
What is a Loop?
A loop allows us to execute a block of code MULTIPLE TIMES based on a condition.
Instead of writing the same lines again and again, loops make code shorter, efficient, and
less error-prone.
Why Do We Need Loops?
Imagine we want to print a name 100 times, without a LOOP, we have to write -
[Link]("Athira");
[Link]("Athira");
[Link]("Athira");

Page 24 of 214
Java Complete Study Notes | By Jatin Sir

// ... and so on, 100 times

Very lengthy and hard to maintain!


With Loop
We can automate repetition efficiently.
(1) Define where to start (initialization),
(2) Set a condition to continue running,
(3) And decide how many times to repeat.
This way, we write less code, avoid repetition, and make our programs clean and maintainable.
Types of Loops in Java
Java provides three main types of loops:
| Loop Type
| --------------| FOR loop
| WHILE loop
| DO-WHILE loop
| Description
Loop Structure
All loops involve these key components:
1️Initialization → Setting up the starting point
2️. Condition
• When to stop the loop
3️. Update/Increment → Progressing toward the stop condition
4️. Body
• The code we want to repeat
For Loop
A FOR LOOP is used when the number of iterations is known in advance.
It has 3 parts:
INITIALIZATION – where the loop starts.
CONDITION – until when the loop should run.
INCREMENT/DECREMENT – how the loop variable updates.
Syntax of a For Loop:
for (initialization; condition; updation) {

// Code to be executed in each iteration

}
How to define a for loop?
for (int i = 1; i <= 2; i++) {

Page 25 of 214
Java Complete Study Notes | By Jatin Sir

[Link]("Java");
}
OUTPUT:
i <= 2. > so output is printed twice!
java
Java
Breakdown of Syntax:
int i = 1; → Initialization (loop starts from 1)
i <= 5; → Condition (loop runs while this is true)
i++ → Updation (i is incremented by 1 after every loop)
What is i++?
i++ means increment i by 1 after each loop cycle.
It’s the same as writing: i = i + 1;
Example: i++ gives 1, 2, 3, 4, 5
Example: i-- gives 5, 4, 3, 2, 1
Looping Variable
"i" is called the LOOPING VARIABLE or CONTROL VARIABLE.
We can name it anything (e.g., j, count, etc.)
Scope Reminder:
The VARIABLE i is accessible only inside the loop.
If we try to use i outside the loop, it results in a COMPILE TIME ERROR.
ERROR: cannot resolve symbol 'i'.
Post vs Pre Increment & Decrement
| Expression | Step 1
| Step 2

Final x Final i

Summary
Post-Increment (i++): Use the value first, then increment.
Pre-Increment (++i): Increment first, then use the updated value.
Post-Decrement (i--): Use the value first, then decrement.
Pre-Decrement (--i): Decrement first, then use the updated value.
Reverse For Loop
When we want to loop backwards, such as printing values from 5 to 1, use reverse for loop.
for (int i = 5; i >= 1; i--) {

// Here, i-- decreases the value of i in each iteration until the condition i >=

Page 26 of 214
Java Complete Study Notes | By Jatin Sir

1 becomes false.
[Link](i);
}
For Loop Without Condition
Gives an INFINITE LOOP as an EXIT CRITERIA is not mentioned.
If we don’t use break, this loop will run forever!
for (int i = 1; ; i++)
For Loop With Multiple Variables
We can declare and update multiple variables in a for loop.
for (int i = 1, j = 5; i <= 5; i++, j--) {
[Link]("i = " + i + ", j = " + j);
}
i = 1, j = 5
i = 2, j = 4
i = 3, j = 3
i = 4, j = 2
i = 5, j = 1
Enhanced For Loop (For-Each)
Used when we just want to read elements of an array/collections one by one, without using an
index.
int[] numbers = {1, 2, 3, 4, 5}; // numbers is an array which holds 5 integer values: 1, 2, 3, 4, 5.
for (int num : numbers) {. // num is a loop variable or Element variable — it temporarily holds
each element of the array numbers during every iteration.
[Link](num);
}
When to Use For Loop?
When NUM OF ITERATIONS is KNOWN.
Great for counting, printing patterns, or accessing array indexes.
Concept Check:
for (int i = 1; i <= 5; i++) {
[Link]("i = " + i);
}
Total Executions - 5
Condition checked - 6 times (n + 1)
In a for loop, if it runs n times, the condition is checked n + 1 times.
Key Points:
Before the loop starts:

Page 27 of 214
Java Complete Study Notes | By Jatin Sir

Java first checks the condition to decide if the loop should even begin.
During the loop:
After each iteration finishes, Java checks the condition again to see if another round should run.
When the loop ends:
Finally, Java checks the condition one more time, sees it’s false, and then stops the loop.
So, for n loop runs, the condition is checked n + 1 times.
While
The while loop is used to execute a block of code repeatedly as long as the condition is true.
Syntax:
while (condition) {

// code block to be executed

}
Flow
Condition is checked first
If true → executes the body
If false → exits the loop immediately
Example 1: Print numbers from 1 to 5
int number = 1;
while (number <= 5) {
[Link](number);
number = number + 1;
}
While Excecution:
| Step | number Value | Condition number <= 5 | Action
📌 Note: Note:
The loop runs as long as the condition is true.
If the condition is false at the start, the loop block won’t run even once.
Infinite loop
int number = 1;
while (number <= 5) {
[Link](number);

// number = number + 1; ← This is missing!

}
What Happens?
number stays 1.

Page 28 of 214
Java Complete Study Notes | By Jatin Sir

number <= 5 is always true, So the loop never exits.


It keeps printing 1 again and again keeping the loop infinite.
Defining Variable Inside a Loop !
Never define a variable inside a loop


for (int i = 1; i <= 5; i++) {
int x = 10;

// x is redefined on every iteration

[Link](x + i);
}
Always define the variable outside the loop:

int x = 10;

// Defined once,

for (int i = 1; i <= 5; i++) {


[Link](x + i); // reusing the same x
}
While with break statement
Normally, a loop ends when its condition becomes false.
But sometimes, we may want to exit early — for example, if a certain value is found or a
condition is met.
In such cases, break gives a manual control to terminate the loop before its natural end.
int i = 1;
while (true) {
if (i == 5) {
break; // Exit loop when i = 5
} else {
[Link]("We are going to be good in Java :-)"); // Prints message
i++; // Update i
}
}
Do-While Loop
The do-while loop excecutes once whether the condition is True or False.
Syntax

Page 29 of 214
Java Complete Study Notes | By Jatin Sir

do {

// Code to execute

} while (condition);
Key Points
The loop executes the block first, then checks the condition.
So, even if the condition is false the first time, the block still executes once.
Often used when you want to take input from the user at least once.
Example
int i = 1;
do {
[Link]("i = " + i);
i++;
}
while (i <= 5);
Output
i=1
i=2
i=3
i=4
i=5
Difference Between while and do-while
When While Condition is Initially False
!
int i = 10;
while (i < 5) {
[Link](i); //
✅ This will print once
i++;
}
Excecution:
The do block runs once no matter what.
i starts at 10.
After printing, i++ makes it 11.
Then while(i < 5) is false → so it exits.
Q1. What is a Loop?
A loop is used to execute a block of code repeatedly until a specified condition is met.

Page 30 of 214
Java Complete Study Notes | By Jatin Sir

Q2. Types of Loops in Java ?


| Loop Type | Condition Check | Executes At Least Once? | When to Use
once** |
Q3. What is the difference between for, while, and do-while
loops in Java?
| Feature
| for loop
| while loop
| do-while loop
After executing the block
least once)
Run block once, then check condition |
Q4. Can we have infinite loops? How do you break them?
Yes, We can create infinite loops with any of the 3 loop types. Use break to exit the loop.
while (true) {
if (Condition)
break;
}
Q5. What happens if the condition is false in a do-while
loop?
The loop executes once, even if the condition is false.
Q6. Can we use break and continue in loops? What’s the
difference?
break: Terminates the loop entirely.
for (int i = 1; i <= 5; i++) {
if (i == 3)
break;
[Link](i);
}

// break example

continue: Skips the current iteration and jumps to the next.


for (int i = 1; i <= 5; i++) { // continue example
if (i == 3)
continue;
[Link](i);
}

Page 31 of 214
Java Complete Study Notes | By Jatin Sir

Q7. Find the o/p ?


for (int i = 1; i <= 5; i++) {
if (i == 3) continue;
[Link](i + " ");
}
Q8. Can we nest loops inside loops?
Yes, nested loops are common in multi-dimensional structures like 2D arrays.
Q9. Find the o/p ?
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 2; j++) {
[Link]("* ");
}
[Link]();
}
Q10. What’s the output of the following code?
int i = 1;
while (i <= 3) {
[Link](i + " ");
i++;
}
Q11. Find the o/p ?
int i = 10;
do {
[Link](i + " ");
i++;
} while (i < 5);
Q12. Find the o/p ?
for (int i = 1; i <= 5; i++) {
if (i == 4) break;
[Link](i + " ");
}
Q13. Find the o/p ?
int i = 1;
while (true) {
if (i == 3) break;
[Link](i + " ");
i++;
}

Page 32 of 214
Java Complete Study Notes | By Jatin Sir

Q14. Find the o/p ?


for (int i = 1; i <= 2; i++) {
for (int j = 1; j <= 3; j++) {
[Link](i + "," + j + " ");
}
[Link]();
}
Q15. When would you use a do-while loop over a while
loop?
Use do-while when the block must run at least once, like menu-based programs or input
validations.
Q16. How can you create an infinite loop using while?
while (true) {
[Link]("This will never stop unless we break");
}
Q17. How do you safely exit an infinite while loop?
Use the break statement inside a condition.
int i = 1;
while (true) {
if (i == 5)
break;
[Link](i);
i++;
}
Q18. What happens if you forget to update the loop
variable?
It causes an infinite loop because the condition never becomes false.
int i = 1;
while (i <= 5) {
[Link](i); // Infinite loop, i never changes

// i++; // Missing update!

}
Q19. Why is it not advisable to declare variables inside a
loop?
A new variable is created in every iteration, wasting memory.
for (int i = 1; i <= 5; i++) {

Page 33 of 214
Java Complete Study Notes | By Jatin Sir

int x = 10; // Created again and again


[Link](x + i);
}
Create variable outside:
int x = 10;
for (int i = 1; i <= 5; i++) {
[Link](x + i);
}
Q20. Can you use break inside a while or do-while loop?
Yes. break helps exit the loop before the condition becomes false.
int i = 1;
while (i <= 10) {
if (i == 5)
break;
[Link](i);
i++;
}
Q21. Write a do-while loop that prints numbers from 10 to 1
in reverse
int i = 10;
do {
[Link](i);
i--;
} while (i >= 1);
Q22. Find the output of the following code?
int x = 5;
while (x > 0) {
[Link](x);
x--;
}
Q23. Find the output of the following code
int i = 10;
do {
[Link](i);
i++;
} while (i < 5);
Q24. What will be the output?
int i = 1;

Page 34 of 214
Java Complete Study Notes | By Jatin Sir

Page 35 of 214
Java Complete Study Notes | By Jatin Sir

Chapter 6: Methods
Method Definition, Parameters, Overloading, Recursion

while (true) {
if (i == 4)
break;
[Link]("Value is: " + i);
i++;
}
Q25. What will be printed?
int i = 0;
while (i < 3) {
i++;
if (i == 2)
continue; // Skips printing when i = 2
[Link]("i = " + i);
}
Mistakes to avoid in Loops
| Mistake
| Example
| Fix
the condition
loop body
{} for clarity
When To Use Which Loop
| Loop
| When to Use
| Common Use Case
Methods
What is a Method?
A method is a code block designed to perform a specific task. It is like an instruction that tells
the program to do something specific, like an action.
Think of it like giving a command to do
something:
print the bill
calculate total
Login with credentials
How to define a method structure ?

Page 36 of 214
Java Complete Study Notes | By Jatin Sir

returnType methodName(argument1, argument2) { // Method Signature // arguments are the


local variables(stored in stack memory) passed into the methods

// What we are going to do inside the method body

}
What is a Method Signature?
Method Signature is - Method Name + Return Type + Parameter List (argument1, argument2)**
int addNumbers(int a, int b)
(argument1, argument2)
↑↑


Return | Argument1 Argument2
Type | (local var) (local var)
Method Name

// Method Name + Return Type + Parameter List

What is a Method Declaration?


What we are going to do inside the braces (code block)!
What is a Return Type ?
The return type tells us what the method will give back after execution (the type). It is specified
before the method name during definition.
Let's learn from
examples!
1. Method With Return Type (int)
Adding two numbers returns a number as result. So int is the return type of this method.
public int addNumbers(int a, int b) { // Adding two numbers returns a number as result. So int is
the return type of this method.
return a + b; // returns sum of two numbers (int)
}
2. Method with Return Type (String)
This method returns name which is of type String.
public String greet(String name) {
return "Hello, " + name + "!"; // returns name which is of type String
}
3. Method with void Return Type
This method performs an action (printing), but doesn't return anything — so the return type is

Page 37 of 214
Java Complete Study Notes | By Jatin Sir

void.
void is a reserved keyword in java.
public void printWelcome() {.

// void is a reserved keyword in java

[Link]("Welcome to Java Learning Journal!"); //This method returns a String


greeting message based on the input.
}
| Real-Life Action
| Method Name (Java)
| Return Type Example | What It Might
Do
| Print the bill
| printBill()
| void
| Prints the bill to a printer or screen
price + tax
welcome message on screen
false based on login status
name and returns full name |
| Read input from user
| readInput()
| String
| Reads and returns user
input from console
and returns the Fahrenheit value
Benefits of Using Methods
REUSABILITY – Write once, use many times. Avoid repeating the same logic.
READABILITY – Code becomes easier to understand and maintain.
MODULARITY – Breaks large programs into smaller, manageable pieces.
Best Practices
Keep methods small and do one task per method.
Create reusable methods to avoid redundancy.
Types of Methods
| Type
| Description
Reading from CSV

Page 38 of 214
Java Complete Study Notes | By Jatin Sir

Taking screenshots
Connecting to a database
Method Excecution in
java
Let's understand the method excecution with the help of a program - Calculator App!
What Do We Need for a Calculator
App?
4. Declare variables with the appropriate type (like `int` or `double`) to store the numbers we
want to calculate.
2. Define a variable to store the result.
5. We'll define these variables **inside the `main()` method, so they become local variables —
stored in **stack memory.
4. Next, we need to create methods like add() and subtract() to perform our calculations.
6. We’ll pass the LOCAL VARIABLES (holding the numbers) as arguments to these methods
so
they can use them.
CalculatorApp
1 public class CalculatorApp {
2
public static void main(String[] args) { // Execution starts here
3
4
double num1 = 100; // Initialization → num1 is a local variable stored in stack
double num2 = 10; // Initialization → num2 is also stored in stack
5
double result;

// Declaration only → holds garbage value since not assigned

// Local variables in Java are not initialized by default

6
double sum = getCalculatedSum(num1, num2);

// Method Call 1: Java says — go and execute this method

// Java searches the method "getCalculatedSum" inside the method first and then inside

Page 39 of 214
Java Complete Study Notes | By Jatin Sir

class, finds method at line 11 → control goes there


7
[Link](sum); // Prints: 110.0
8
double diff = getCalculatedDiff(num1, num2);

// Method Call 2: control goes to line 15

9
10
11
12
13
14
15
16
17
18
19 }
[Link](diff); // Prints: 90.0
}
public static double getCalculatedSum(double num1, double num2) {

// Control from line 6 reaches here → this method is pushed to the stack

double result = num1 + num2; // result = 100 + 10 = 110


return result;

// The result (110) is returned to result is returned back to the caller // line 6 and
assigned to variable 'sum'

// Garbage value from line 5 is replaced with 110

} // Method ends → popped from stack → control returns to line 7


public static double getCalculatedDiff(double num1, double num2) {

// Control from line 8 reaches here → this method is now pushed to stack

double result = num1 - num2; // result = 100 - 10 = 90

Page 40 of 214
Java Complete Study Notes | By Jatin Sir

return result;

// Returns 90 to line 8 and assigned to variable 'diff'

} // Method ends → popped from stack → control returns to line 9


How Method works Internally ?
Main Method Execution Starts at (Line 2)
At line 2, the main() method is pushed to the stack.
num1 = 100 and num2 = 10 are local variables stored in stack memory
result is declared but not initialized, so it holds a garbage value
+--------------------------+
| main()
| ← top
| num1 = 100
+--------------------------+
top in stack means - This is the method currently executing
Why is the main() method able to
directly call getCalculatedSum() or
getCalculatedDiff()?
The main() method is always declared as public static.
In Java, a static method can directly call another static method in the same class without using
an object reference.
Calling getCalculatedSum(num1,
num2) - Line 6
At line 6, java calls the method getCalculatedSum(num1, num2) - Method call
Java search for the method inside the method first and then inside the class
Control goes to Line 11 and the getCalculatedSum () in line 11 is pushed to top of the stack
Values of num1 and num2 from the main are passed into this method.
Result is calculated and returned to the caller method - Line 7
Once the method completes, it is popped off (removed) from the stack and control goes to Line
8.
+----------------------------------+
| getCalculatedSum()
| ← top
executing
| num1 = 100
+----------------------------------+
| main()

Page 41 of 214
Java Complete Study Notes | By Jatin Sir

+----------------------------------+
top in stack means - This is the method currently
Calling getCalculatedDiff(num1, num2)
• Line 8
At line 15, java calls the method getCalculatedDiff() - Method call
Java search for the method inside the method first and then inside the class
Control goes to Line 15 and the getCalculatedDiff () is pushed to top of the stack
Values of num1 and num2 from the main are passed into this method.
Result is calculated and returned to the caller method - Line 9
Once the method completes, it is popped off (removed) from the stack and control goes to Line
8.
+----------------------------------+
| getCalculatedDiff()
| ← top** top in stack means - This is the method currently
executing
| num1 = 100
+----------------------------------+
| main()
+----------------------------------+
Final Stack (Just Before Program
Ends)
+------------------------------+
| main()
| ← top
| num1 = 100
In final stack, sum and diff store actual results,but "result" in main() still holds garbage bcs
nothing was assigned to it.
| sum = 110
+------------------------------+
All lines in main() executed
No more methods to call
At this point:
• All local variables (num1, num2, sum, diff, result) are cleared from memory.
• The main() method is popped off the stack.
• Stack becomes empty.
• The Java program ends gracefully.
Wrapper Class in
Java
What is a Wrapper Class? Why Do We

Page 42 of 214
Java Complete Study Notes | By Jatin Sir

Need It?
Think of this: You're on an international trip to Amsterdam .
You carry local currency, but to shop or dine abroad, you need Euros (€) — the local currency
there.
So, you convert your local currency to Euros to be able to function smoothly during your trip.
In Java, it's similar - Java is an object-oriented language, and while primitive types like int, char,
and boolean are simple and fast (like local currency), they cannot be used in places where
objects (Euros) are required.
Since Java Collections (like ArrayList, HashMap) and many utility classes and APIs are
designed to work with objects, primitives like int, char, and boolean cannot be used directly
in those contexts.
That’s where Wrapper Classes come in — they act like a currency converter , WRAPPING
THE PRIMITIVE into an OBJECT form so it can be used where only objects are allowed.
Analogy Summary:
| Concept
| Example | Analogy
How Can We Define a Wrapper Class?
A Wrapper Class is an object representation of a primitive type.
Primitive vs Wrapper Types
Wrapper Class Features
int num = 10;

// Primitive

Integer numObj = 10; // Wrapper class


• Part of [Link] package
• Immutable, like Strings
• Allow primitive types to be used as Objects.
• Wrapper → stored in heap
Primitive vs Wrapper Comparison
| Feature
| Primitive Type | Wrapper Class
No
Yes
No
Yes
No
Yes
No

Page 43 of 214
Java Complete Study Notes | By Jatin Sir

Yes








Visual Comparison
| primitive | int num1 = 10;
Wrapper | Integer num2 = 10;

Stores `10` directly in variable Stores a reference to object holding `10`

Why Do We Need Wrapper Classes?


7. Collections like `ArrayList<int>` won’t work with primitives → use `ArrayList<Integer>`
2. Allow null values
3. Provide utility methods like parseInt()
8. For object-oriented features like **autoboxing**, **null handling**, and **generics**
> int is faster but Integer is flexible for OOP and Collection use
Don’t worry if Collections are new to you — you'll understand this even better in the
Collections section of the journal.
Use of Wrapper in Collections
Generics (type) in Java require objects — they don’t accept primitive types. That’s why
we use wrapper classes:

// List

List<Integer> integerList = new ArrayList<>(); // Here Generics is Integer

// Set

Set<Double> doubleSet = new HashSet<>();

// Here Generics is Double

// Map

Page 44 of 214
Java Complete Study Notes | By Jatin Sir

Map<Integer, String> studentMap = new HashMap<>();

// Queue

Queue<Character> charQueue = new LinkedList<>(); // Here Generics is Character

// Stack

Stack<Float> floatStack = new Stack<>();

// Here Generics is Float

// PriorityQueue

PriorityQueue<Long> longQueue = new PriorityQueue<>();

// Deque

Deque<Short> shortDeque = new LinkedList<>();


These are examples of using wrapper classes with various generic data structures in
Java.
Concept cHECK
● What is a Wrapper Class in Java?
● Why do we need Wrapper Classes when we already have primitive types?
● List all primitive types in Java and their corresponding wrapper classes?
● Can you assign null to a wrapper class?
● What is autoboxing and unboxing in Java? Give examples.
● How are primitives and wrappers stored?
● What’s the default value of Object?
● Are wrapper classes immutable?
● Can you extend a wrapper class?
● How is memory handled differently for primitive types and wrapper classes?
● What are the default values of wrapper class objects vs primitive types?
● What is the difference between == and .equals() when comparing wrapper
objects?
● What are the performance implications of using wrapper classes instead of
primitives?
● Can you override methods on wrapper classes like Integer or Boolean?

Page 45 of 214
Java Complete Study Notes | By Jatin Sir

● Can wrapper classes be used in switch-case statements?


What is Type Casting
?
Type casting is the process of converting a variable from one data type to another.
In Java, this can happen automatically (widening) or manually (narrowing).
1. Implicit Type Casting (Widening
Conversion)
Implicit Type Casting happens automatically.
Java converts a smaller data type to a larger data type without any data loss . It is also
called Widening Casting
Implicit Conversion Order:
byte → short → int → long → float → double
Wondering how does implicit
conversion happens automatically ?
And how is a smaller type
automatically assigned to a larger
one?
Real-Life Use of Implicit Conversion
Calculating Average
we want a decimal result, even though the number starts as an integer.
int totalMarks = 450;

// int

int subjects = 6;

// int

double average = totalMarks / subjects; // double


[Link](average); // Output: 75.0 in double
How this works?
totalMarks and subjects are both int, so: Java performs integer division: 450 / 6 → 75 (int).
We're assigning the result to a double: double average = 75;
Java checks:
Can I safely store an int (like 75) inside a double? Why Java Allows This (Implicit Widening).
double has more storage (8 bytes) than int (4 bytes).
double can represent both whole numbers and decimal numbers (e.g., 75.0). There's no risk of
data loss. So Java automatically converts int to double.
What is Explicit Conversion? And

Page 46 of 214
Java Complete Study Notes | By Jatin Sir

when is it needed?
Explicit casting is when we manually convert one data type to another using (type) syntax —
especially when automatic conversion doesn't happen or we want more control.
We tell Java exactly what type to convert to by writing the type in parentheses.
When we explicitly cast totalMarks from int to double, this forces Java to treat totalMarks as a
double (455.0) before doing the division.
int totalMarks = 455;
int subjects = 6;

// Implicit Conversion

double average1 = totalMarks / subjects; // Here, Java performs integer division: 455 / 6 → 75
(decimal .833 is lost)

// Explicit Casting

double average2 = (double) totalMarks / subjects;// Explicit Casting - Here, we are telling java,
please treat totalMarks as a double before doing the math.
[Link]("Implicit: " + average1); // Output: 75.0
[Link]("Explicit: " + average2); // Output: 75.833333...
What happens Internally ?
double average2 = (double) totalMarks / subjects
Here, (double) totalMarks is a double operand. One operand is double, so Java promotes the
other (subjects = 6) to double automatically.
So the final division becomes: 455.0 / 6.0 → 75.833333...
The result is stored in average2, which is a double.
Method Overloading
Method Overloading means creating multiple methods within the same class with
the same name, but with different parameters.
How Java Decides Which Method to
Call in method overloading?
Java looks at:
(1) The number of parameters
(2) The data types of parameters
(3) The order of data types in parameters**
This decision happens at compile time
Calculator - Using Method Overloading
01 public class CalculatorApp {
02 public static void main(String[] args) { / Excecution starts here

Page 47 of 214
Java Complete Study Notes | By Jatin Sir

03
int a = 10;
04
int b = 20;

// local variables assigned with explicit values // stored in stack

05
int c = 30;
06
double d = 5.5;
07

// Method calls

08
09
10
11
12
addNumbers(a, b);
addNumbers(a, b, c);
addNumbers(d, b);

// Call 1

// Call 2

// Call 3

// Overloaded method 1: two ints

13
14
15
16

Page 48 of 214
Java Complete Study Notes | By Jatin Sir

17
18
19
private static void addNumbers(int x, int y) {
[Link]("Sum (int + int): " + (x + y));
}

// Overloaded method 2: three ints

private static void addNumbers(int x, int y, int z) {


[Link]("Sum (int + int + int): " + (x + y + z));
}
20

// Overloaded method 3: double and int

21 private static void addNumbers(double x, int y) {


22
[Link]("Sum (double + int): " + (x + y));
23 }
24 }
How method overloading works
Internally?
Method Call on Line 8: addNumbers(a, b) → Control goes to
Line 13 as it matches the method on Line 13.
main() starts

├── Line 8: addNumbers(10, 20)
│ └── Java looks for method: addNumbers(int, int)
│ └── Matches Line 13
│ └── Values pushed to stack:

┌────────────┐

│ x = 10 │ ← copied from main()'s a

│ y = 20 │ ← copied from main()'s b

└────────────┘

Page 49 of 214
Java Complete Study Notes | By Jatin Sir

│ └── Executes Line 14 → Output: Sum (int + int): 30


│ └── Method excecution finishes - Values popped out of Stack - Control returns to the caller
(main method)

At Line 8, local variables a and b are passed by value into x and y.
Local variables from main() are copied into method arguments - Java's pass-by-value
behavior.
Method Call on Line 9: addNumbers(a, b, c) → Control goes
to Line 17 as it matches the method on Line 17
main() continues

Page 50 of 214
Java Complete Study Notes | By Jatin Sir

Chapter 7: Arrays
Single & Multi-Dimensional Arrays, Traversal


├── Line 9: addNumbers(10, 20, 30)
│ └── Java looks for method: addNumbers(int, int, int)
│ └── Matches Line 17
│ └── Values pushed to stack:

┌────────────────┐

│ x = 10
│ ← from a

│ y = 20
│ ← from b

│ z = 30
│ ← from c

└────────────────┘
│ └── Executes Line 18 → Output: Sum (int + int + int): 60
│ └── Method excecution finishes - Values popped out of Stack - Control returns to the caller
(main method)

At Line 9, a, b, and c are passed by value into x, y, and z
Local variables from main() are copied into method arguments - Java's pass-by-value behavior.
Method Call on Line 10: addNumbers(d, b) → Control goes
to Line 21 as it matches the method on Line 21
main() continues

├── Line 10: addNumbers(5.5, 20)
│ └── Java looks for method: addNumbers(double, int)
│ └── Matches Line 21
│ └── Values pushed to stack:

┌────────────┐

Page 51 of 214
Java Complete Study Notes | By Jatin Sir

│ x = 5.5 │ ← from d

│ y = 20 │ ← from b

└────────────┘
│ └── Executes Line 22 → Output: Sum (double + int): 25.5
│ └── Method excecution finishes - Values popped out of Stack - Control returns to the caller
(main method)

At Line 10, d and b are passed by value into x and y.
Local variables from main() are copied into method arguments - Java's pass-by-value
behavior.
Key Points:
Method overloading happens inside the same class.
The return type does not affect method overloading.
Java does not care about private, static, void, or modifiers when overloading.
Only the method signature (name + parameter list) matters.
Why Return Type Doesn’t Matter in
Overloading?
In Java, we do not use return type to differentiate overloaded methods.
If overloading were allowed based on return type alone, it would lead to ambiguity — the
compiler would have no way to decide which method to execute during a method call.
int show() {
return 10; // return type is int
}

// both methods have same name.

double show() {
return 10.5; // return type is double
}
Even though both methods return different types (int and double), they have the same method
name and have no parameters.
When we call show() >> The compiler cannot tell which version of show() we're referring to.
Java will throw an error because it only uses the method name and parameter list to resolve
calls — not the return type.
Arrays
What is an Array?

Page 52 of 214
Java Complete Study Notes | By Jatin Sir

An array is a LINEAR DATA STRUCTURE in Java that stores multiple values of the same data
type in contiguous memory locations.
Arrays allow you to access data efficiently using an index.
📌 Note: Note : Data Structure is a way of organizing and storing data in memory so that it
can be used
efficiently.
Key Characteristics
| Concept
| Explanation
elements.|
| COMMOM ERROR.
| Accessing an invalid index causes
ArrayIndexOutOfBoundsException.
How to Define an Array ?
Single Dimensional Array
int[] arr = new int[5];

// Array definition with size

int[] marks = {90, 80, 70, 60}; // Array definition without size - array literal syntax (automatically
set based on the number of values)
9. int [ ] → Declares an array that will store integers.
10. arr → Is the reference variable, stored in the stack.
11. new int[5] → Allocates 5 contiguous memory locations in the heap.
4. Each element is automatically initialized to 0 (default value for int)
How Array is stored in memory?
Stack Memory
Heap Memory
arr ────────────────►
[ 0 ][ 0 ][ 0 ][ 0 ][ 0 ]
Index: 0 1 2 3 4
How to Add Elements in an Array ?
We add elements to an array by assigning values to specific indexes.
int[] arr = new int[5]; // Creates an array of size 5
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
arr[3] = 40;
arr[4] = 50;

Page 53 of 214
Java Complete Study Notes | By Jatin Sir

How Array Looks in Memory After


Adding Elements?
int[] arr = new int[5];
Index:
Value:
[0] [1] [2] [3] [4]
[10 ] [20 ] [30 ] [40 ] [50 ]
How to access elements in an array?
Array elements are accessed using index numbers. Indexing starts from 0 and goes up to length
• 1.
int[] marks = {90, 80, 70, 60};
[Link](marks[0]); // Accessing 0th index - Output: 90
[Link](marks[3]); // Accessing 3rd index - Output: 60
What Happens If You Access an
Invalid Index?
If we try to access an index outside the valid range, Java throws a runtime exception called
ArrayIndexOutOfBoundsException
int[] marks = {90, 80, 70, 60};
[Link](marks[4]); //
❌ This will throw ArrayIndexOutOfBoundsException
Why ArrayIndexOutOfBoundsException occurs?
Because marks[4] is invalid — the array has only 4 elements (index 0 to 3).
length property in Arrays
In Java, every array has a built-in length property that tells us how many elements the array can
hold.
int[] arr = new int[5];
[Link]([Link]); // Output: 5
Key Points
length is a property, not a method, no parentheses ().
It returns the total number of elements the array can store.
Indexing goes from 0 to length - 1.
int[] arr = new int[5];
Index:
[0] [1] [2] [3] [4]


First Index
Last Index = [Link] - 1

Page 54 of 214
Java Complete Study Notes | By Jatin Sir

[Link] = 5
Array Traversing Using For Loop
Array traversing means moving through an array from the first index (0) to the last index (length
• 1) to access each element.
int[] nums = {10, 20, 30, 40};
for(int i = 0; i < [Link]; i++) {
instead of hardcoding i < 3

// Best Practise : Use i < [Link] for dynamic range

[Link](nums[i]); // helps in printing, searching, sorting, or performing operations


on array elements.
}
Notes:
i < [Link] is preferred over hardcoding (i < 4).
If you use i <=, make sure to write i <= [Link] - 1 to avoid
ArrayIndexOutOfBoundsException.
Array Traversing Using Enhanced For
Loop
The enhanced for loop is used when: We want to visit every element in the array.
We don’t need index here!
int[] marks = {90, 80, 70, 60};
for (int mark : marks) {. // mark is the loop variable that temporarily holds each element from

Page 55 of 214
Java Complete Study Notes | By Jatin Sir

Chapter 8: Strings
String Class, Intern Pool, Immutability, String Methods

the marks array during each loop cycle.


[Link](mark);
}
Points:
What is mark here? mark is a temporary variable (also called a loop variable).
It represents the current element of the marks array during each iteration.
Its type (int) must match the type of the array elements.
2D Arrays
A 2D array in Java is like a table with rows and columns.
int[][] arr = new int[2][2]; // 2 rows, 2 columns
12. int[][]
Declares a 2D array that will store integers in rows and columns format.
13. arr is the reference variable, stored in the stack, pointing to the 2D array in heap.
14. new int[2][3] - creates a 2D array with 2 rows and 3 columns (total 6 elements) in the heap
memory.
4. Default Values - All elements are automatically initialized to 0 (default value for int).
↓ columns
01
┌─────────
0│ 0 0
1│ 0 0

rows
Assigning Values to a 2D Array
arr[0][0] = 10;
arr[0][1] = 20;
arr[1][0] = 30;
arr[1][1] = 40;
Now the array looks like:
01
┌──────────
0 │ 10 20
1 │ 30 40
Traversing a 2D Array
for (int rowIndex = 0; rowIndex < [Link]; rowIndex++) {

Page 56 of 214
Java Complete Study Notes | By Jatin Sir

rows

// [Link] ➤ gives number of

for (int colIndex = 0; colIndex < arr[0].length; colIndex++) {


of columns (for that row)

// arr[0].length ➤ gives number

[Link](arr[rowIndex][colIndex] + " ");


}
[Link]();
}
Disadvantages of Array!
1. Fixed Size
Once declared, the size of an array cannot be changed.
You either run out of space or waste memory if the size is not planned correctly.
2. No Inbuilt Methods
Java arrays do not offer built-in methods for common operations like:
Searching, Sorting, Inserting or deleting elements
All of these must be done manually or with helper methods.
3. Insertion and Deletion are Hard
Inserting a new element in the middle or deleting one means:
Shifting elements manually or Updating indexes carefully
There’s no automatic shifting or resizing.
4. Must Track Indexes Manually
You need to remember and manage indexes to avoid ArrayIndexOutOfBoundsException.
There's no method like get(index) or remove(index) as in Lists.
5. Stores Only Homogeneous Data
Arrays are type-specific:
An int[] can store only integers.
A String[] can store only strings.
We can't mix types like in ArrayList<Object>.
String
A String is a sequence of characters. Eg: "java". ( String should be enclosed in double quotes)
String is a class from the [Link] package. It is a non-primitive data type .
How to declare a String?
2 ways to declare a String - (1) Using String Literal and (2) Using new Keyword (String Object)
(1) Using String Literal

Page 57 of 214
Java Complete Study Notes | By Jatin Sir

S in caps non -primitive variable




String name = "Every Second Counts";


└───────► String Literal
variable.


Literal is a fixed value assigned to a

└───────► reference var // Stores memory address (reference) — acts as unique
identification to locate the object

non-primitive Datatype
(2) Using new Keyword (String Object)
We can create a String Object using the new keyword. [ new keyword creates object in
Heap Memory]
1. String s1 = new String("Java");
2. String s2 = new String("Java");
Stack Memory
Heap Memory
┌────────────┐
┌────────────────────┐
│ s1
│──────────────►│ "Java" (object) │
└────────────┘
└────────────────────┘
┌────────────┐
┌────────────────────┐
│ s2
│──────────────►│ "Java"(object) │
└────────────┘
└────────────────────┘
reference variables
What happens in here?
new String("Java") creates a new object in the Heap.

Page 58 of 214
Java Complete Study Notes | By Jatin Sir

One object is created in the heap for s1.


Another separate object is created in the heap for s2.
Each call to new creates a separate object in heap memory - meaning s1 and s2 point to
different memory addresses, even though their content is the same.
Where is this String Literal stored in
Memory?
String literal is stored in a special memory called STRING INTERN POOL.
STRING INTERN POOL lets us store only unique value (No duplicates) - Efficient memory
usage.
How Java Stores String Literals in the
Intern Pool ?
15. public static void main(String[] args()){
2. String Name1 = "Alexa";
3. String Name2 = "Alexa"; // Sring Literal is stored in String Intern Pool
}
Excecution Flow
Stack Memory:
String Intern Pool:
+----------+
+---------+
| main() | TOP
| 777 | <- (Memory Address)
+---------+
^

777 name2 (Reference) -----------------

+----------+
Program Execution Starts from main() >> The main method is loaded into the stack memory
(Top of the Stack).
>> Line 2: String Name1 = "Alexa";
Java checks if "Alexa" is already present in the String Intern Pool - NO, it is not present >> so
"Alexa" is added to the String Intern Pool.
A reference is created for Name1 in the stack (777), pointing to the memory address of "Alexa"
(777) in the String Intern Pool.
>> Line 3: String Name2 = "Alexa";
Java checks if "Alexa" is already present in the String Intern Pool. >> YES, it is already there.
Java assigns the same reference (memory address - 777) to Name2, pointing to the same

Page 59 of 214
Java Complete Study Notes | By Jatin Sir

memory location as Name1, as String Intern Pool do not allow duplicates.


What is the purpose of String Intern
Pool ?
To save memory by reusing immutable string literals.
String is an Immutable Class - What
Does That Mean? How String
Immutability Works?
String is an immutable class, which means that once a String object is created, its value cannot
be changed.
Any modification of a String results in the creation of a new String object, leaving the original
one unchanged.
16. public static void main(String[] args()){
2. String Name1 = "Alexa";
3. String Name2 = "Alexa"; // Sring Literal is stored in String Intern Pool
4. String Name1 = Name1 + Name2; // Concatenation operation - adding 2 strings.
}
Excecution Flow
Stack Memory:
String Intern Pool:
+----------+
+---------+
| main() | TOP
| 888
| <- (Memory Address)
+---------+

777 name2 (Reference) --------------------

+---------+
| "Alexa " | 777 String Intern Pool
+---------+
Line 2: String Name1 = "Alexa";
The string "Alexa" is stored in the String Intern Pool. The reference Name1 now points to the
memory address of "Alexa" in the intern pool.
Line 3: String Name2 = "Alexa";
Since "Alexa" is already in the String Intern Pool, Name2 points to the same memory address as
Name1.[ shown in image 1]
Line 4: Name1 = Name1 + Name2; //Alexa Alexa

Page 60 of 214
Java Complete Study Notes | By Jatin Sir

This line performs String concatenation, adding Name1 ("Alexa") and Name2 ("Alexa") - The
result is "Alexa Alexa".
Java checks if "Alexa Alexa" already exists in the String Intern Pool. Since it doesn't, Java adds
"Alexa Alexa" to the pool.
>> Important: Now, Name1 points to a new memory reference 888 (where "Alexa Alexa" is
stored) and the previous reference (777) pointing to "Alexa" is removed.
How Does Java Compare Objects?
Java compares objects in two ways:
(1) Using the reference comparison operator ==
(2) Using the .equals() method
How Reference Comparison Operator
( == ) Compare Primitives ?
>For primitive types (like int, char, boolean, etc.), == compares the actual values stored in the
variables, not memory addresses.
int a = 10; // a is primitive type
int b = 10; // b is primitive type
[Link](a == b); // == compares values for primitives // true because both values are
same. [ 10 == 10]
For Primitive types (like int, char, boolean)
Reference Comparison Operator ( == )compares actual values stored in the variable.
How Reference Comparison Operator
( == ) Compares Non - Primitives ?
For non-primitive types, == compares the memory address (i.e., whether two reference
variables point to the same object in memory)
String s1 = new String("Java"); // s1 - reference variable
String s2 = new String("Java"); // s2 - reference variable
[Link](s1 == s2); // false → different memory addresses
s1 and s2 are reference variables in the stack, each pointing to separate objects (i.e., different
memory addresses) in the heap, both containing the same content: "Java".
String s3 = "Java"; // s3 is stored in the String Intern Pool
String s4 = "Java"; // s4 points to the same object as s3, since the content is identical
[Link](s3 == s4); // true → both refer to the same object in the String pool
.equals() method
Used to compare contents of objects**
The .equals() method is case-sensitive.**
String s1 = new String("Java");
String s2 = new String("Java");
String s3 = new String("JAVA");

Page 61 of 214
Java Complete Study Notes | By Jatin Sir

[Link]([Link](s2)); // true → same content (case matches)


[Link]([Link](s3)); // false → content is not the same (case difference - the
uppercase and lowercase letters do not match.)
What is hashCode() ?
Every object in Java has a hashCode() method (inherited from Object class, which is the parent
of all classes in java).
It returns an integer value that represents the object’s hash .
> For Strings: The String class OVERRIDES hashCode() to return a VALUE based on its
CONTENT, NOT MEMORY LOCATION
String s1 = "Athira";
String s2 = new String("Athira");
[Link]([Link](s2));

// true → same content

[Link]([Link]());

// e.g., 63365123

[Link]([Link]());

// same as s1 → 63365123

Even though s1 and s2 are different objects in memory, their hashCodes match because their
CONTENTS ARE EQUAL.
Why is String Non-Primitive?
Unlike primitive types (int, char, etc.), String is a class. So we can create object from a class.
Even when declared like a primitive (String name = "java";). It internally creates a String object.
We can use methods on String (e.g., .length(), .toUpperCase()) — which primitive types don’t
support.
Memory Allocation: String Literal vs
String Object
String Literal
String name = "Athira"; // String Literal
Stored in the String Intern Pool.
> If the same literal already exists, Java reuses the reference → memory efficient.
String Object using new
String name = new String("Athira"); //String Object
A new object is created in Heap memory, even if the same literal exists in the pool > Not

Page 62 of 214
Java Complete Study Notes | By Jatin Sir

memory efficient.
How It Looks Internally In Memory?
Heap Memory
------------| "Athira" | ← created by new
------------String Intern Pool
---------------------| "Athira" | ← already created if not present
---------------------Stack Memory
----------------------------| name ─────────┐

| Reference to Heap

-----------------------------
Why do we prefer String Literals over
String Objects?
String Literals - We prefer String literals because they are stored in the String Pool,which helps
Java reuse existing strings instead of creating new objects.
This improves memory efficiency and performance.
String Object - Using new String() creates unnecessary objects in Heap memory,so it is
generally avoided unless we explicitly need a new instance.
String Summary (Quick Revision)
(1) String is immutable → Once created, it cannot be changed.
(2) String literals are stored in the String Intern Pool.
(3) Using new String("abc") creates a new object in Heap memory.
(4) .equals() compares content.
(5) == behaves differently:
> For primitives: compares actual values
10 == 10 → true
> For objects: compares memory/reference
"abc" == new String("abc") → false
(6) .hashCode() returns an int based on content (overridden in String class)
(7) .hashCode() checks the content
(8) Different memory → == returns false
(9) Strings are thread-safe by nature due to immutability
Brain Teasers !
public class StringCheck {
public static void main(String[] args) {
String a = "Be Consistent";
String b = new String("Be Consistent");
[Link](a == b);

Page 63 of 214
Java Complete Study Notes | By Jatin Sir

// ?

[Link]([Link](b)); // ?
[Link]([Link]()); // ?
[Link]([Link]()); // ?
}
}
Questions:
(Q1) a == b → Does it compare references or values?
(Q2) [Link](b) → Will it return true or false? Why?
(Q3) [Link]() and [Link]() → Will they match?
public class EqualityCheck {
public static void main(String[] args) {
int a = 10; // primitive
int b = 10;
[Link](a == b); // ?
String s1 = "Value your time";
String s2 = new String("Value your time");
[Link](s1 == s2); // String object
[Link]([Link](s2)); // ?

// ?

}
}
(Q1) What will be the output of a == b? Why?
(Q2) Are s1 and s2 referring to the same object in memory? Why or why not?
(Q3) What does s1 == s2 compare? Content or memory reference?
(Q4) Why does [Link](s2) return true even though s1 == s2 is false?
(Q5) How many objects are created in memory when we write new String("Value your time")?
(Q6) Why does == work differently for primitives and String objects?
String Intern Method

Page 64 of 214
Java Complete Study Notes | By Jatin Sir

Chapter 9: Object-Oriented Programming (OOP)


Classes, Objects, Encapsulation, Constructors

String Intern Pool Vs Heap


String Literal - String Intern Pool
String data = "Nothing is impossible"; // string literal
String Intern Pool stores String literals.
Before creating a new literal, Java checks if it already exists in the pool.
If yes, the same reference is reused (memory efficiency).
If not, a new literal is added to the pool.

-------------------
String Object - Heap
String data = new String ("Nothing is impossible");
Heap stores objects created with new String().
Even if the same string exists in the pool, new forces a new object in the heap.
String .intern() in Java - What it does ?
We can explicitly move a String object to the String Intern Pool by calling .intern().
intern() tells Java - Put this string in the String Intern Pool - and return the reference from the
pool.
If the string already exists in the pool → Java won’t duplicate it, it will just return the existing
reference.
If it doesn’t exist yet → Java adds it to the pool and return that reference.
public class InternExample {
public static void main(String[] args) {
String s1 = "Nothing is impossible";

// goes to intern pool

String s2 = new String("Nothing is impossible"); // new object in heap


String s3 = [Link]();

// refers to "Nothing is impossible" from pool

[Link](s1 == s2); // false → different references


[Link](s1 == s3); // true → both point to pool "Nothing is impossible"
}
}
Excecution Flow

Page 65 of 214
Java Complete Study Notes | By Jatin Sir

String s1 = "Nothing is impossible";


"Nothing is impossible" is stored in the intern pool.
s1 points to the string intern pool.
String s2 = new String("Nothing is impossible");
Creates a new heap object, even though "Nothing is impossible" is already in the pool.
So s2 points to a different object.
String s3 = [Link]();
intern() checks the pool. "Nothing is impossible" already exists.
Instead of adding a duplicate, it returns the reference from the pool.
Now s3 points to the same object as s1.
Why we always create String literal
and not string object?
string literals
String s1 = "hello";
String s2 = "hello";
Stored in the String Intern Pool.
When a new literal is created, Java first checks if the same value already exists in the pool.
If it exists → Java reuses the reference instead of creating a new object.
Saves memory and improves performance.
string objects
String s1 = new String("hello");
String s2 = new String("hello");
Each new String call always creates a new object in heap memory, even if the same value
already exists in the pool.
This leads to duplicate objects with the same content → more memory usage.
The object inside heap is separate, but Java still creates/uses a copy of the literal in the intern
pool internally.
Concept Check
1. What does the intern() method do in Java?
Moves a String object from the heap to the String Intern Pool.
If the string already exists in the pool, it returns the reference instead of creating a new one.
2. What is the return value of intern()?
Returns a reference to the string from the intern pool.
String s1 = new String("java");
String s2 = [Link]();
String s3 = "java";
[Link](s2 == s3); // true
3. What is the difference between new String(abc) and

Page 66 of 214
Java Complete Study Notes | By Jatin Sir

[Link]()?
new String(abc) → creates a new object in the heap (even if abc already exists in the pool).
[Link]() → ensures the string is placed in the intern pool and returns the reference.
4. Does intern() always create a new object?
No. If the string already exists in the intern pool, it just returns the reference.
If not, it adds it to the pool and returns the new reference.
Classes & Objects
OOPS
Object-Oriented Programming (OOP) is a way of writing programs by grouping data (variables)
and behavior (methods) into objects.
It makes code easier to understand, reuse, and maintain.
Principles of OOPS
(1) Classes and Objects (2) Encapsulation (3) Abstraction (4) Polymorphism (5) Inheritance
What is a Class?
Classes are rules imposed on an object.
ie class is a blueprint or set of rules that defines how objects behave and what they can do.
What is an Object?
An object is a real-world entity that occupies memory space.
Objects are created → They should follow the rules → They perform various actions → When
tasks are completed → Objects are destroyed.
Class vs Object - Real World Example
Car is an object, a real world entity. When we create a Car object, it must follow the rules
defined in the Car class.
Car class defines rules like maximum speed, number of wheels, type of fuel, braking system.
Actions (methods) could be: start(), accelerate(), brake(), refuel().
Properties (variables) could be: color, speed, fuelType.
Real Object with Class's Properties
and Methods!
From this blueprint (class), we can create different Car objects A black car with a speed of 110
km/hr that can start, accelerate, brake, and refuel.
A white car with a speed of 200 km/hr that can start and accelerate.
This shows how an object is a real instance of a class, with its own unique property values but
the same set of actions defined by the class.
Class, Object, and Methods —
Explained with a Student Example
17. package [Link];
18. public class Student { // Student is the class name
3.
19. int age;

Page 67 of 214
Java Complete Study Notes | By Jatin Sir

20. int rollNumber;


21. double marksObtainedInEnglish;

// variables created inside the class → instance

variables - stored in Heap memory


7. String name;

// instance variables are properties of class

22. double marksObtainedInMaths;


23. double marksObtainedInScience;
10. String grade;
11.
24. // Functionality → task / Non - static Method - which performs calculation of marks
25. public void calculateTotalMarks() { // Method name should describe the action it performs
14.
double totalMarks = marksObtainedInEnglish + marksObtainedInMaths +
marksObtainedInScience;
15.
[Link]("Total Marks Obtained: " + totalMarks); // print the result
26. }
27. }
Instance Variables
Variables created inside a Class are called Instance variables - age,
rollNumber,marksObtainedInEnglish, marksObtainedInMaths, marksObtainedInScience,Grade.
They are non - static.
Instace variables are implicitly initialized with default values.
Stored in Heap Memory.
Role of main() in program excecution .
To execute the program, we need a main method.
Best practice → Name the executable class as Runner (class containing the main method).
28. package [Link];
29. public class Runner {

// Class that contains the main method

3.
30. public static void main(String[] args) { // Entry point of the program
5.

Page 68 of 214
Java Complete Study Notes | By Jatin Sir

int x = 10;

// Local variable in stack memory

6.
int[] y = new int[3];

// Array object in heap, reference in stack

7.
Student s1 = new Student(); // Creating a Student object in heap
31. }
32. }
Local Variable
Variables created inside a method are called Local Variables.
• They are stored in stack memory.
• Java does not initialize them with default values — we must assign a value before using
them,
otherwise we'll get a compile-time error.
• Their lifetime is only until the method finishes execution, after that, they are removed from
the
stack.
public void show() {
int x; // Local variable, no default value
[Link](x); // Compile-time error: variable x might not have been initialized
}
Program Execution Flow
Java executes the program line by line:
Line 1 → package [Link];
A package is like a folder that groups related classes together.
It also helps avoid name conflicts between classes with the same name in different projects.
Line 2 → public class Runner
java enters this class only if it has a valid main method.
Line 4 → public static void main( )
Execution starts here.
main() method is pushed into the stack memory.
The stack top pointer now points to main().
+---------------------------+
| main()

Page 69 of 214
Java Complete Study Notes | By Jatin Sir

| ← top pointer
+---------------------------+
Line 5 → int x = 10;
java excecutes RHS first → evaluate 10.
Type check → Is 10 an integer?
✅ Yes. Is it stored in an int variable? ✅ Yes.
Allocate 4 bytes for x in stack (inside main’s stack frame).
java intialize 10 to x.
Stack Memory
+---------------------------------------+
| main() is pushed into the stack
top -> | main() | x = 10
+---------------------------------------+
Line 6 → int[] y = new int[3];
java executes RHS first → new int[3] creates an array object in the heap with 3 memory slots.
Since an array is a non-primitive type, Java automatically initializes all elements to their default
values. (For int, the default value is 0)
When the array is created in the heap, it gets a memory address (e.g., 999).
When Java executes the LHS, this address is stored in y (in the stack), so y now points to
that array in the heap.
Line 7 → Student s1 = new Student();
Student s1 = new Student();
Student - user defined data type
s1 = reference variable
new Student() - Object
java excecutes RHS first - new Student() creates an object student in heap memory
java executes RHS first → new Student():
new keyword = always creates a new object in the heap.
When ever an object is created 3 things happen Step 1: Student class is loaded into memory called
Method Area
Method Area - Stores class-level information — not per-object data.
Method Area is part of JVM memory from the start, but it’s empty until classes are
loaded.
Created when the class is first loaded by the JVM (before any object is created).
Step 2: Instance variables are created in heap and initialized with default values.
Step 3: Constructor is called (if not defined, Java provides a default constructor and executes it).
The object’s memory address (e.g., 101) is created.
LHS → s1 is a reference variable in stack; it stores the address/hashcode (e.g., 101) pointing to

Page 70 of 214
Java Complete Study Notes | By Jatin Sir

the Student object in heap.


Stack Memory
Heap Memory
+------------------------+ +------------------------------------+
| main
| | 101 (Student object)
= null

s1 ---> 101 -----------+--->

+------------------------+ | | maths
=0
= null
=0
+------------------------------------+
Line 8 → } (method closing brace)
Marks the end of the main() method.
When main() ends, the stack frame for main is removed (popped) from the stack memory.
All local variables (x, y, s1) are destroyed — but the objects they pointed to in heap remain in
memory until garbage collection runs.
Stack Memory (after main ends)
+---------------------------+
+---------------------------+
Line 9 → } (class closing brace)
Marks the end of the Runner class.
At this point, program execution is complete (unless there are other threads running).
📌 Note: Note:
All instance variables in heap get default values based on their type.
A real Student object is created in heap memory with its own name, age, rollNumber, marks,
etc., ready to be used by the program, and can be accessed using the reference variable s1.
Accessing instance
Variables
What are Instance Variables?
Instance variables are variables declared inside a class but outside any method, constructor, or
block.
Instance variables are stored in heap memory along with the object, and if not explicitly
initialized, they are automatically assigned default values.
class Student {

Page 71 of 214
Java Complete Study Notes | By Jatin Sir

String name; // instance variable


int age;

// instance variable

double marks; // instance variable


}
Part 1 – Defining Instance Variables in
a Class
This class defines the properties (instance variables) of a Student. These variables are stored in
heap memory when an object is created.
33. package [Link];
34. public class Student { // Student is the class name
3.
35. int age;
36. int rollNumber;
37. double marksObtainedInEnglish;

// variables created inside the class → instance

variables - stored in Heap memory


7. String name;

// instance variables are properties of class

38. double marksObtainedInMaths;


39. double marksObtainedInScience;
10. String grade;

// Functionality → task / Non - static Method - which performs calculation of marks

40. public void calculateTotalMarks() { // Method name should describe the action it performs
12.
double totalMarks = marksObtainedInEnglish + marksObtainedInMaths +
marksObtainedInScience;
13.
[Link]("Total Marks Obtained: " + totalMarks); // print the result
41. }
42. }
Part 2 – Creating an Object and

Page 72 of 214
Java Complete Study Notes | By Jatin Sir

Accessing Instance Variables


This Runner class creates a Student object and shows how to access its instance variables
using a reference variable.
43. package [Link];
44. public class Runner {

// Class that contains the main method

45. public static void main(String[] args) { // Entry point of the program
4.
int name; // Local variable — stored in Stack
5.
6.
Student s1 = new Student(); // Object in Heap, reference (s1) in Stack
7.
[Link](s1);

// Prints: [Link]@hashcode (in

hexadecimal) — it's the hashcode from [Link]()


8.
9.

// Accessing instance variables

10.
[Link]([Link]); // Prints 'null' (default value)
11.
[Link]([Link]); // Prints 0 (default value)
46. }
47. }
Recap on what happens during an
object creation!
---------------------------Student s1 = new Student();
-----------------------------RHS : new Student();
Java executes RHS first → new Student()
new keyword = always creates a new object in the heap.
A new object is created in heap memory.
When an object is created in the heap, 3 things happen in order:

Page 73 of 214
Java Complete Study Notes | By Jatin Sir

Step 1: The Student class is loaded into memory called Method Area.
Method Area - Stores class-level information — not object data.
Method Area is part of JVM memory from the start, but it’s empty until classes are
loaded.
class loading into the Method Area happens only the first time when we use that
class in our program. Class loading is done by class loader
Step 2: Instance variables for that object are created in heap and initialized with default
values (e.g., int = 0, String = null).
Step 3: Constructor is called.
If no constructor is defined, Java provides a default no-arg constructor and executes it.
Constructor then sets the instance variables to the values we specify (if any).
The object’s memory address (e.g.101 or a hashcode) is created internally.
LHS : Student s1
s1 is a reference variable stored in the stack.
It holds the address/hashcode that points to the object in heap.
Now, Let's understand - What is a
reference variable ?
Imagine we have a locker in a gym.
The locker contains our gym shoes, water bottle, and towel (locker is our object with its items =
instance variables).
We don’t carry the entire locker around. Instead, we are given a locker key with a number
written on it.
That key doesn’t hold the items itself — it just points to where our locker is in the gym.
In Java terms:
Object = The locker (where all instance variables live).
Reference variable = The locker key (knows the location of the locker in memory).
Instance variables = The items inside the locker (the actual data).
We can have multiple keys (references) to the same locker (object), but the data is still stored in
one place.
No matter how many keys we have, they all open the same locker and see the same things
inside.
If we change something in the locker using one key, the change is visible to anyone using the
other keys.
What happens if we print reference
variable - s1?
[Link](s1); // o/p - [Link]@512ddf17
Printing a reference variable gives the hashcode generated by the hashCode() method
Hashcode > [Link]@512ddf17

Page 74 of 214
Java Complete Study Notes | By Jatin Sir

[Link] → The package name where the Student class is


located.
Student → The class name of the object.
@ → Separator between the class name and the hashcode.
512ddf17 → The hashcode of the object, represented in hexadecimal (base 16).
How to access instance variables?
We can access instance variables using the object reference variable followed by a dot (.) and
the variable name.
If we haven’t assigned any value yet, Java prints the default value for that variable’s type.
[Link]([Link]); // Prints 'null' (default value of String)
[Link]([Link]); // Prints 0 (default value of age)
How to assign values to instance
variabels?
48. package [Link];
49. public class Runner {
3.

// Class that contains the main method

50. public static void main(String[] args) { // Entry point of the program
5.
6. Student s1 = new Student(); // Object creation
51. [Link] = "Neil"; // Assigning values to instance variables
52. [Link] = 10;
53. [Link] = 30;
54. [Link] = 50;
55. [Link] = 48;
56. [Link] = 47;
57. [Link] = "A";
58. [Link]([Link]); // Retrieving the value of 'name' and printing it
15. [Link]([Link]);
59. [Link]([Link]); //Retrieving the value of 'rollNumber' and printing it
17. [Link]([Link]);
60. [Link]([Link]); // Retrieving the value of 'name' and printing
it
19. [Link]([Link]);
20. [Link]([Link]);
61. [Link]();
How this value assignment happens ?

Page 75 of 214
Java Complete Study Notes | By Jatin Sir

Line 6
Student s1 = new Student();
An object is created in heap memory, and its instance variables are allocated space and
initialized with default values.
Stack Memory
Heap Memory
+---------------------------+
+-----------------------------------+
| main()
= null
=0
= null
+---------------------------+
+---------------------------+---+
Line 7
[Link] = "Neil";
Java checks where s1 is stored — it’s a local variable in stack memory (s1 is a local variable
inside main() method).
In the stack, s1 holds the value 777 (a reference/address pointing to the object in heap).
Java follows this reference 777 into the heap memory to locate the Student object.
Inside that object, Java finds the name instance variable.
The default value null is replaced with "Neil".
Same process happens for Lines 8–13:
How to retrieve values from instance
variables?
14. [Link]([Link]); // retrieving values by printing it off
15. [Link]([Link]);
16. [Link]([Link]);
17. [Link]([Link]);
18. [Link]([Link]);
19. [Link]([Link]);
20. [Link]([Link]);
Line 14
[Link]([Link]);
Java looks in the stack memory for the variable s1.
It finds that s1 holds the reference value 777 (hashcode/address of the object in heap).
Using this reference, Java goes to the heap memory and locates the Student object.
It checks if the object has a variable named name — Yes.

Page 76 of 214
Java Complete Study Notes | By Jatin Sir

Java retrieves the current value stored in name ("Neil") and prints it to the console.
Now We Understand –How Are
Objects and Classes Related?
We first created the Student class — this is like a blueprint.
The class only describes what a student has (properties) and can do (methods).
To actually use these properties, we need to create an object from the class.
After creating the object, we can assign values to its variables and use its methods.
In short:
A class is the plan — like a blueprint of a student, describing properties like name, age, marks,
and grade, and methods like calculating total marks.
An object is the real thing made from that plan — a real student with an actual name, age,
marks, and grade.
What Are the Problems or Drawbacks
Here?
Right now, instance variables in our Student class can be accessed directly from outside the
class.
This means anyone can assign invalid values to them without any checks.
Example:
Setting age = -110 — clearly invalid, but nothing stops us from doing it.
Setting rollNumber = 0 — may not be valid for our system.
Setting grade = "ABC" — might not match our allowed grading system.
62. [Link] = "123@Neil";
63. [Link] = -110;
64. [Link] = 0;
65. [Link] = "ABC";

// Assigning invalid name

// Invalid age

// Invalid roll number

// Invalid grade format

Key issue:
Direct access to instance variables breaks control over the data and can lead to incorrect or
inconsistent objects.

Page 77 of 214
Java Complete Study Notes | By Jatin Sir

What Is the Solution to This Invalid


Value Assignment Problem?
The solution is Encapsulation.
Encapsulation means hiding the internal details of a class (its variables) and allowing access
only through controlled methods.
we will see it in detail in the next section with examples.
Encapsulation
What is encaspsulation ?
Encapsulation protects the instance variables from invalid value assignments, which is achieved
through public getter and setter methods by writing the validation logic.
Real World Example
In a bank, there’s a minimum balance rule — say ₹5,000.
minium balance = 5000;
And if the minimum balance is not maintained, bank will charge a monthly fine of 500.
Without encapsulation, someone could set minBalance = 0, and suddenly no one gets charged
the ₹500 penalty for not maintaining balance — costing the bank millions.
class BankAccount {
int minBalance = 5000; // Rule for maintaining minm balance
void showMinBalance() {
[Link]("Minimum Balance Required: ₹" + minBalance);
}
}
public class Runner {
public static void main(String[] args) {
BankAccount account = new BankAccount(); // object creation // creating a real account
[Link](); // ₹5000

// Anyone can directly change it to an invalid value

[Link] = 0; // changed the balance to 0


[Link](); // 0 → Rule broken!
}
}
How can we achieve Encapsulation?
We can achieve encapsulation - by declaring the instance variable private.
"private" means - instance variables can be accessed only inside the class. So that no one can
assign illegal values to instance variables.
class BankAccount {

Page 78 of 214
Java Complete Study Notes | By Jatin Sir

private int minBalance = 5000; // private instance variable


What happens if we access the private
variable in the main Runner class?
public class Runner {
public static void main(String[] args) {
BankAccount account = new BankAccount();
[Link] = 0; // Compile-time error
}
}
java gives error message Error in Intellij - minBalance has private access.
Error in Eclipse - Field minBalance is not visible
Reason: private variables can only be accessed within the class where they are declared.
Access from outside (even in the same package) is not allowed without public methods
(getters/setters).
How can we access a private variable
inside main()?
we can access private instance variables inside main - by Using public methods such as
getters and setters.
Getter → Retrieves the value of a private instance variable.
Setter → Assigns a value to a private instance variable, passed as a parameter.
Can include validation logic to ensure only valid values are stored.
By using getters and setters, we achieve encapsulation.
Code showing setters() and getters()
package [Link];
public class Student {
private String name;
private int age;
private int rollNumber;

// Getter and Setter for name

public String getName() {


return name;
}
public void setName(String name) {
[Link] = name; // this initialize the instance variabe with the value we are passing
}

// Getter and Setter for age

Page 79 of 214
Java Complete Study Notes | By Jatin Sir

public int getAge() {


return age;
}
public void setAge(int age) {
if (age < 21 && age >= 10) {. // Validating age
[Link] = age;
} else {
[Link]("Invalid Age for Student!!");
}
}

// Getter and Setter for rollNumber

public int getRollNumber() {


return rollNumber;
}
public void setRollNumber(int rollNumber) { // validating rollnumber
if (rollNumber >= 1) {
[Link] = rollNumber;
} else {
[Link]("Invalid Roll Number");
}
}
Student Runener class
package [Link];
public class StudentRunner {
public static void main(String[] args) {

// Create Student object

Student s1 = new Student();

// Set values using setters

[Link]("John Doe");
[Link](15);
[Link](101);

Page 80 of 214
Java Complete Study Notes | By Jatin Sir

// Get and print values using getters

[Link]([Link]());
[Link]([Link]());
[Link]([Link]());
}
}
How to achieve encapsulation in java?
Declare instance variables private - It controls access to instance variables from outside the
class.
Provide public getter and setter methods - It prevents invalid assignments by validating values
before storing them.
How to add setetrs and getters in our
code?
1. Right-click inside your class file.
2. Select SOURCE (or use the menu bar: Code → Generate).
3. Click Generate Getters and Setters.
4. Select the fields you want to generate them for.
5. Click OK — the IDE will auto-create the methods.
This Keyword
This keyword is used to differentiate local variables with instance variables when they have the
same name.
Student Class
66. package [Link]; // Package hierarchy: com (domain) →
student → management → system → oops
67. public class Student { // Student is the class name
3.
68. private int age;

// Instance variables (fields) — stored on the heap as part of the

object creation
69. private int rollNumber;
70. private double marksObtainedInEnglish;

// variables created inside the class →

instance variables
71. private String name;

Page 81 of 214
Java Complete Study Notes | By Jatin Sir

// instance variables are properties of class

72. private double marksObtainedInMaths;

// instance variables are always assigned with

default values when created


73. private double marksObtainedInScience;
74. private String grade;
75. public String getName(){. // Getter: returns the student's name
76. return name;
}
77. public void setName() {. // setname - To assign name
14 [Link] = name;

// assigning value from the method parameter 'name' to the

instance variable 'name'


78. }
16.
79. public void setRollNumber(int rollNumber){ // Setter with validation: only accept positive roll
numbers
18.
80. if(rollNumber >=1)

// validation inside setter method

20.
[Link] = rollNumber;
81. }
82. else{
23. [Link]("Invalid roll number");
83. }
25.

// Functionality → task / Non - static Method - which performs calculation of

marks
84. public void calculateTotalMarks() { // Method name should describe the action it performs

Page 82 of 214
Java Complete Study Notes | By Jatin Sir

27.
double totalMarks = marksObtainedInEnglish + marksObtainedInMaths +
marksObtainedInScience;
28.
[Link]("Total Marks Obtained: " + totalMarks); // print the result
85. }
86. }
Runner Class
87. package [Link];
88. public class Runner {

// Class that contains the main method

89. public static void main(String[] args) { // Entry point of the program
4.
5.
6.
Student s1 = new Student(); // Object in Heap, reference (s1) in Stack
7.
8.
[Link]("Joe")// setmethod to set name
[Link](-10);
9.
10.

// Accessing instance variables

11.
[Link]([Link]()); // Prints 'null' (default value)
12.
[Link]([Link]()); // Prints 0 (default value)
90. }
91. }
Program Excecution
Java executes code line by line starting from the class that contains the main() method.
The main() method is the program’s entry point and runs first when the application starts.
Line 1 (Runner Class):
package [Link] - Class "Runner" belongs to this package.
Line 2 (Runner Class) :

Page 83 of 214
Java Complete Study Notes | By Jatin Sir

public class Runner {


Runner is a public class (public is called access modifier - public is a keyword in java)
{ - opening braces of class - It is the entry point of a class.
Line 3 (Runner Class):
public static void main(String[] args) > main method
For java to excecute the runner class, It should go inside main method.
Main method is excecuted in stack
Line 6 (Runner Class):
Student s1 = new Student();
RHS : new Student();
Java executes RHS first → new Student()
new keyword = always creates a new object in the heap.
A new object is created in heap memory.
When an object is created in the heap, 3 things happen in order:
Step 1: The Student class is loaded into memory called Method Area.
Method Area - Stores class-level information — not object data.
Method Area is part of JVM memory from the start, but it’s empty until classes are
loaded.
class loading into the Method Area happens only the first time when we use that
class in our program. Class loading is done by class loader
Step 2: Instance variables for that object are created in heap and initialized with default
values ([Link] = 0)- say object's hashcode is 777.
Step 3: Constructor is called.
If no constructor is defined, Java provides a default no-arg constructor (dummy constructor) and
executes it.
The object’s memory address (e.g.777 or a hashcode) is created internally.
Now, java excecutes the left side LHS : Student s1
Student is the data type and s1 is a reference variable stored in the stack.
s1 holds the address/hashcode (777) that points to the object in heap.
Stack Memory
Heap Memory
+---------------------------+
+-----------------------------------+
| main()
= null
| | these are all private instance
variables which can't be accessed outside the class
=0

Page 84 of 214
Java Complete Study Notes | By Jatin Sir

= null
+---------------------------+
+---------------------------+---+
Setter Method – How It Works
Why We Need Setters ?
Instance variables are usually declared as private to protect them from direct access outside the
class, This prevents illegal value assignments from outside.
But then, how do we assign values to these private variables from outside?
By using setter methods - To assign values
Getter methods - For reading values.
Line 7 (Runner Class):
[Link]("Joe"); // Control goes to Line 13 in Student class - setName method()
Stack and Heap During setName("Joe") Execution - before the assignment to heap variable
happens
+----------------------------+
+-------------------------------+
Stack
Heap
+----------------------------+
+-------------------------------+
top-> | setName("Joe")
+----------------------------+
+----------------------------+
+-------------------------------+
s1 is a reference variable in the stack pointing to a Student object in the heap.
When we call [Link]("Joe") > Java pushes the setName method into the stack for
execution. (All methods are always executed inside the stack)
top points to setName() as its the top most in stack - and the method currently running.
[Link]("Joe") tells Java: Look at the object that s1 is pointing to. Go into its class (Student)
and execute the method named setName.
At the moment setName starts running, the parameter variable "name" is CREATED INSIDE
STACK of setName and stores the value "Joe".
(Method parameters are local variables and are always stored in the stack.)
📌 Note: Remember - When we created the "Student" object - a "name" variable is created
in heap.
Two Variables Named "name"
So now, we have two different variables with the same name - "name":
(1) One in the stack → method parameter.

Page 85 of 214
Java Complete Study Notes | By Jatin Sir

(2) One in the heap → instance variable of the object.


There is no conflict because they are in different memory locations.
Line 13 (Student Class):Role of "this"
Keyword !

// when java excecutes >> [Link]("Joe") >> Control goes to Line 13 in Student class
setName method()

"This" keyword helps to differentiate local variables with instance variables.


To assign the value from the local variable (stack) to the instance variable (heap), we use - "this"
keyword.
"this" keyword - always refers to instance variable.

// [Link]("Joe") --> Control goes to Line num 13 in Student class

92. public void setName(String name) { // name in parameter is a local varaible


93. [Link] = name; // value of local variable is assigned to instance variable

// "[Link]" → instance variable in heap

// name = local variable

94. }
[Link] → refers to the instance variable in heap. [with "this" keyword - It explicitly tells java
that we are referring to the instance variables of the class]
name → refers to the local variable in stack.
What If We Skip "this"?
public void setName(String name) {
name = name; // Both refer to the local variable → does nothing!
}
Java will confuse both variables as local variables.
The instance variable will never get updated.
After [Link] = name -> How it looks
in memory?
+----------------------------+
+-------------------------------+
Stack (
Heap
+----------------------------+

Page 86 of 214
Java Complete Study Notes | By Jatin Sir

+-------------------------------+
| setName("Joe")
+----------------------------+

(instance variable)

+----------------------------+
+-------------------------------+
Line 15 (Student Class)
} – Closing brace for the setName method.
At this point, Java pops the setName method frame out of the stack.
Now, only main() remains in the stack, and top points back to main().
Line 8 (Runner Class)
95. [Link](-22);// Control goes to Line 17 in student object
s1 is a reference variable in the stack pointing to student object in the heap.
When we call setRollNumber(-10), Java pushes the setRollNumber method into the stack for
execution.(setRollNumber is a method - methods are always excecuted inside stack)
[Link](-10) tells Java - Look at the object s1 is pointing to, Go into its class (Student)
and execute the method named setRollNumber.[Line 17 in Student class]
Roll num (local variable) is set as -10 inside the stack .
Line 17 (Student Class) - How
validation works inside setter?
96. public void setRollNumber(int rollNumber){
18.
97. if(rollNumber >=1)
20.
[Link] = rollNumber;
98. }
99. else{
23. [Link]("Invalid roll number");
100. }
java will excecute Line num 17 - java checks the validation written inside the setRollNumber
method
(1) Is rollNumber > 1? OR (2) Is rollNumber = 1 ?
Both condition are false >> So java is not going to excecute
So [Link] = rollNumber >> assignment won't happen and java will excecute else block
• and print - Invalid roll number.
"RollNumber" in heap will remain 0 as its default value.

Page 87 of 214
Java Complete Study Notes | By Jatin Sir

When wrong values are rejected in a setter, the instance variable keeps its old value — which
could be the default value if no valid assignment has been made yet.
Line 24 (Student Class)
} - closing brace
end of setName method
java pops out the setName method rom the stack.
We only have main() inside the stack and top will point to the main()
Constructors
What is a Constructor?
A constructor is a special method in a class, which has the same name as the class name.
What s the job of the constructor?
The job of the constructor is to initialize instance variables during object creation.
How to create a constructor in an IDE
(IntelliJ/Eclispse)?
Open class file in the editor.
Place the cursor inside the class but outside any existing methods.
Right-click → select Source → Generate Constructor using Fields.
What is a default constructor?
It’s the constructor Java provides automatically if we don’t write any constructor in our class.
It has no parameters and no body code .
class Student {
int age;
String name;

// Default constructor (automatically created by Java):

// Student() { super(); }

}
Student Class - How constructor in a
class look like?
101. package [Link];
102. public class Student { // Student is the class name
3.
4.
int age;

// variables created inside the class → instance variables - stored in Heap

Page 88 of 214
Java Complete Study Notes | By Jatin Sir

memory
5.
int rollNumber; // instance variables are properties of class // cannot be static
6.
String name; // instance variables are assigned with default values, if not initialized
7.
103. public Student(String name, int age, int rollNumber) {
10.
11.
12.
13.
[Link] = name;
[Link] = age;
[Link] = rollNumber;

// Constructor - has same name as the class

// parametres in the constructor - are local variables - created in stack memory

// constructor with parameter is called parameterized constructor

14.
15.
16.
17.
18.
[Link] = marksObtainedInEnglish;
[Link] = marksObtainedInMaths;
[Link] = marksObtainedInScience;
[Link] = grade;
}
19.
public void setRollNumber(int rollNumber){ // added a setter with validation for rollnumber
104. if(rollNumber >=1)
21.
[Link] = rollNumber;

Page 89 of 214
Java Complete Study Notes | By Jatin Sir

105. }
106. else{
24. [Link]("Invalid roll number");
107. }
108. }
Student Runner Class
package [Link];
public class Runner {
public static void main(String[] args) {
Student s1 = new Student("Neil", 10, 26, 40, 30, 41, "B");// // Object creation → calls the
constructor and assigns values to instance variables
[Link]("John"); // Setter updates the 'name' instance variable from "Neil" → "John"
[Link](-10); // Setter validation fails → rollNumber remains 26 (from constructor)
[Link]([Link]());
[Link]([Link]());
}
}
What happens during Object creation?
During object creation - we pass all the values of instance variables, and constructor pass it and
use it for assigning to instance variables.
Student s1 = new Student("Neil", 10, 26, 40, 30, 41, "B");
Constructor is called ONCE - ONLY DURING OBJECT CREATION.
2. How is Constructor different from
Setter ?
------------------------------------------------------------------------------------------------------------------------------------
-----| Constructor
| Setter
-------------------------------------------------------------------------- |
| Constructor is Called ONLY ONCE during object creation. | Setter can be called MULTIPLE
TIMES after object creation.
object creation.
the programmer.
| Example: new Student("Neil", 17, 25)
| Example - [Link]("Uday")
------------------------------------------------------------------------------------------------------------------------------------
-------
Properties of Constructors
(1) Has the same name as the class.
(2) No return type (not even void).

Page 90 of 214
Java Complete Study Notes | By Jatin Sir

(3) Called automatically at object creation.


(4)Used for initial assignment of instance variables.
Types of Constructors
Default Constructor
Has no parameters.
If we don’t write any constructor, Java provides a default one.
public Person() {
[Link]("Default Constructor");
}
Parameterized Constructor
Accepts parameters to initialize instance variables.
public Person(String name, int id) {
[Link] = name;
[Link] = id;
}
Copy Constructor
Copy Constructor creates a copy of an existing object of the same class. Parameter is usually
another object of the same class.
public Person(Person other) {
input
[Link] = [Link];
[Link] = [Link];
}

// Copy constructor: takes another Person object as

// Copy 'name' from the given object

// Copy 'id' from the given object

public static void main(String[] args) {


Person p1 = new Person("John", 1); // Normal constructor
Person p2 = new Person(p1);

// Copy constructor → p2 is a copy of p1

Page 91 of 214
Java Complete Study Notes | By Jatin Sir

Constructor Overloading
Multiple constructors with same name inside a class but with different parameter lists.
public Person() { }

// Default

public Person(String name) { }

// 1 parameter

public Person(String name, int id) { } // 2 parameters


Constructor Chaining
When one constructor calls another constructor using this() or super(), It is called constructor
chaining.
When we call one constructor inside another constructor, It should be the first line.
this() – calls another constructor in the same class.
super() – calls a constructor from the parent class.
public Person(String name, int id) {
this(); // Calls default constructor
[Link] = name;
[Link] = id;
}
What is the benefit of Constructor
overloading?
We want to give flexibility when creating objects :
> Sometimes we may only know the name.
> Sometimes both name and id.
Private Constructors - why we need
private constructors?
When we make a constructor private - we cannot create object outside the class.
Used to restrict object creation from outside the class.
commonly used in:
Singleton design pattern (only one object allowed).
Utility/helper classes (e.g., Math class in Java) to prevent object creation.
When we make a constructor public - we can create object outside the class.
private Person() {
}
Code Execution - Constructor
109. class Student {

Page 92 of 214
Java Complete Study Notes | By Jatin Sir

2. String name;
110. int age;
4.
5. Student(String name, int age) {

// Constructor

6.
[Link] = name; // Assign parameter to instance variable in Heap
7.
[Link] = age;
111. }
9.
112. public static void main(String[] args) {
11.
Student s = new Student("Neil", 10); // Object creation - constructor is called
113. }
114. }
Execution Steps: How Constructor
Assigns Values to Instance Variables
1. main() starts in Stack memory.
○ Program begins with main method.
○ main() is loaded into the Stack memory.
+----------------------+
+----------------------+
| Stack
top ->| main()
+----------------------+
2. Reference variable s created in Stack.
○ Code: Student s = new Student("Neil", 10);
○ s is a reference variable stored in the Stack.
○ It will point to the Student object in the Heap.
○ new Student(...) creates an object in Heap > new keyword allocates
memory in Heap.
○ Instance variables (name, age) are created with default values.
Step 2: new Student("Neil", 10) creates object in Heap
Step 2: new Student("Neil", 10) creates object in Heap
+----------------------+
+-------------------------------+

Page 93 of 214
Java Complete Study Notes | By Jatin Sir

Stack
Heap
+----------------------+
+-------------------------------+
3. Constructor is called, when the obj is created → parameters go to Stack.
● Constructor Student(String name, int age) runs.
● A stack is created for the constructor.
● Parameters ("Neil", 10) are stored as local variables in Stack.
+----------------------+
+-------------------------------+
Stack
Heap
+----------------------+
+-------------------------------+
4. Values copied from Stack to Heap's instance variables. [Link] = name; //
assigns "Neil" [Link] = age; // assigns 10
○ The local variable 'name' in Stack (value = "Neil") is assigned to the
instance variable 'name' in Heap.
○ The local variable 'age' in Stack (value = 10) is assigned to the instance
variable 'age' in Heap.
5. When the Constructor finishes excecution→ local variables disappear.
○ Constructor is removed from stack.
○ Local variables in Stack are gone.
○ Heap object remains with values updated.
6. Object remains in Heap, referenced by s in Stack.
○ s in Stack holds the reference (e.g., 777).
○ That points to the Student object in Heap.
○ Object lives as long as a reference exists.
Bringing It All
Together: Setters,
Getters &
Constructors →
POJO
Now that we have learned:
(1) How to make variables private ?
(2) How to create public setter and getter methods ?
(3) How to define constructors to initialize objects ?
It’s time to bring all of these together to create something powerful yet simple — a POJO class!

Page 94 of 214
Java Complete Study Notes | By Jatin Sir

What is a POJO Class?


POJO stands for Plain Old Java Object.
A POJO class is used to map and convert external data formats (like JSON or XML) into Java
objects and vice versa.
It's a simple Java class used mainly to HOLD DATA.
It is a simple Java class that:

> Only contains PRIVATE VARIABLES


> Uses GETTERS and SETTERS to access those variables
> May include a CONSTRUCTOR to initialize values
> Has NO logic, NO inheritance, NO annotations, NO framework-specific code
Basically, it’s just a CLEAN CONTAINER OF DATA
POJO Class Example
To store info about a person - name and age:
public class Person {
private String name; //private instance variables
private int age;

// Constructor

public Person(String name, int age) {


[Link] = name;
[Link] = age;
}

// Getter for name

public String getName() {

Page 95 of 214
Java Complete Study Notes | By Jatin Sir

Chapter 10: Inheritance & Polymorphism


IS-A Relationship, Method Overriding, super keyword

return name;
}

// Setter for name

public void setName(String name) {


[Link] = name;
}

// Getter for age

public int getAge() {


return age;
}

// Setter for age

public void setAge(int age) {


[Link] = age;
}
}
That’s a POJO!
No logic, no extends, no implements, no annotations > just pure data holding.
Summary: POJO
| What does a POJO contain?
toString() Method in Java
What is toString()?
toString() is a method that converts an object into a string representation - It returns an one line
description of the object's instance variables.
toString() is defined in the Object class, which is the parent of all Java classes.
ToString Method - Code - How the o/p
looks like?
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", rollNumber=" + rollNumber + "]";

Page 96 of 214
Java Complete Study Notes | By Jatin Sir

}
OUTPUT - Student [name=Neil, age=10, rollNumber=30]
Without toString() - What is going to be
the o/p?
s1 is the reference variable which store hashcode of the object
If we print s1 without toString() - [Link](s1) - s1 returns hashcode >>
[Link]@512ddf17
Why use toString()?
Helps during debugging or logging, so we can see the exact values of variables.
Without overriding, calling [Link](obj) prints the hashcode by default.
Overriding allows printing meaningful data about the object.
How toString() looks internally (inside
Object class) ?
public String toString() {
return getClass().getName() + "@" + [Link](hashCode());
}
What happens step by step ?
getClass().getName() >> Gets the runtime class of the object (e.g., Person, Student, Car).
Example → "Person"
hashCode() >> Returns a unique number (int) that represents the object in memory.
Example → 2052879
[Link](hashCode()) >> Converts that number into hexadecimal format.
Example → "7a81197d"
Then it combines them like: Person@7a81197d
Output (default):
Person@7a81197d
Summary
toString() exists in Object class, so all Java objects have it.
Default → className@hashCode.
Overriding → meaningful object data.
Best practice → always override toString() for user-defined classes.
How to Compare
Java Objects equals() &
Hashcode() !
class Student {
private String name;
public Student(String name) {
[Link] = name;

Page 97 of 214
Java Complete Study Notes | By Jatin Sir

}
}
public class MainApp {
public static void main(String[] args) {
Student s1 = new Student("Anu");
Student s2 = new Student("Ann");
Student s3 = new Student("Ann");

// Comparing two objects using .equals()

[Link]([Link](s2));
[Link]([Link](s3));
same

// false - content not same

// true - content same // value of instance variable

}
}
equals()
equals() is a method used to compare two objects in java.
2 objects are said to be equal > When they belong to the same class type.
> values of instance variables should be same
> 2 objects are going to have same hashcode
📌 Note: NOTE: When 2 objects are equal >> they will have same hashcode value!
Internal representation of .equal()
@Override
public boolean equals(Object obj) { // comparing 2 objects// parameter is of parent class//
datatype of reference is obj

// Step 1: Check if both references point to the same object

if (this == obj) { // this talks about the current instance// comparing [Link](s1)
return true; // then return true!
}

// Step 2: Check if the passed object is null

Page 98 of 214
Java Complete Study Notes | By Jatin Sir

if (obj == null )// passing null - couldn't compare which doesn't exist ie obj reference is
NULL
return false; // return false!

// step 3: ocheck if the passed obj is of the same class

if(getClass() != [Link]()) { // getClass() gives the class type // if 2 classes are not
equal - return false
return false; // return false
}

// Then do type casting - after that value of each instance variable of one object is

compared with other one.


Where do we use .equals() in
Automation Framework?
.equals() is commonly used in assertions to compare expected and actual results
Student expectedData = new Student("Ann", 20, 18, 75, 82, 69, "B");
[Link](expectedData);
Student actualData = new Student("Ann", 20, 18, 75, 82, 69, "B");
[Link]([Link](actualData)); // true → if equals() is properly
overridden
Inheritance
Inheritance teaches - ' IS A ' relationship.
Inheritance is the relationship between similar entities.
Inheritance is a parent–child relationship, where the child class (subclass) can acquire
the properties and behaviors (variables and methods) of the parent class (superclass)
WITHOUT CREATING THE OBJECT.
Parent: Person has name, age.
Child: Student → automatically gets name, age from Person without rewriting.
Why Inheritance?
Reduces code duplication
Improves maintenance
Represents a parent–child relationship between classes.
Inheritance - Parent & child
Relationship
CHILD uses KEYWORD "extends" to inherit parent's properties.
Parent is called SUPER CLASS

Page 99 of 214
Java Complete Study Notes | By Jatin Sir

Child is called SUB-CLASS


class Parent {

// variables & methods

}
class Child extends Parent {

// can use parent's non-private variables & methods

}
📌 Note: Important Terms
Superclass (Parent Class) → the class whose properties are inherited.
Subclass (Child Class) → the class that inherits the parent’s properties.
Child can only access non-private features of the parent.
Types of Inheritance
Single Inheritance - One child inherits
from one parent.
Class A (Parent)
Class B (Child)
class A
{
}
class B extends A
{
}
Multilevel Inheritance
Class A (Grandparent)
Class B (Parent)
Class C (Child)
class A { }
class B extends A { }
class C extends B { }
Multiple Inheritance (Not Supported in
Java)
Class A
Class B
\
/

Page 100 of 214


Java Complete Study Notes | By Jatin Sir

Reason: Ambiguity
Solution: Use Interfaces if multiple inheritance is needed.
\
/
\
/
Class C ← Error
How to define instance variables in
parent class when a child class
extends the parent?
We use "protected" as access modifier, so that child classes can directly access parent class
variables, while still keeping them hidden from the outside world.

// Parent class

class Person {

// protected → accessible in child classes, but not outside the package

protected String name;


protected int age;
}

// Child class inheriting parent class

class Student extends Person {


private int rollNo; // child’s own variable
}
Constructor Chaining (with super())
If the parent class has a PARAMETERIZED CONSTRUCTOR:
>> It is the job of the child class to call the parent's constructor with SUPER keyword - It is
called Constructor chaining.
>> It ensures that the parent portion of the object is initialized first before the child’s own
members are set.
When we create an object of child class → parent class constructor runs first, then child
constructor.
This ensures the parent is always initialized before the child.
constructor chaining happens with 2 keywords
> this keyword - calls constructor within the same class

Page 101 of 214


Java Complete Study Notes | By Jatin Sir

> super keyword - to call parent class constructor from child class constructor
Class Student (child) extends Person
(parent)
1 class Person {
2 protected String name; protected int age;
3
4 // Constructor 1 (overloaded)
5 public Person(String name) {
6
[Link] = name;
7
[Link] = 18; // default
8
[Link]("Parent Constructor 1 (name only)");
9}
10
11 // Constructor 2 (overloaded)
12 public Person(String name, int age) {
13
[Link] = name; [Link] = age;
14
[Link]("Parent Constructor 2 (name and age)");
15 }
16 }
17
18 class Student extends Person {
19 int rollNo;
20
21 // Child constructor → calls parent Constructor 2
22 public Student(String name, int age, int rollNo) {
23
super(name, age); // super() → calls parent Constructor 2
24
[Link] = rollNo;
25
[Link]("Child(Student) constructor called");
26 }
27

Page 102 of 214


Java Complete Study Notes | By Jatin Sir

28 // Another Child constructor → calls parent Constructor 1


29 public Student(String name, int rollNo) {
30
super(name); // super() → calls parent Constructor 1
31
[Link] = rollNo;
32
[Link]("Child(Student) constructor called (via super(name))");
33 }
34 }
Runner Class
1 public class Runner {
2 public static void main(String[] args) {
3
Student s1 = new Student("Athira", 25, 101); // → calls parent Constructor 2
4
Student s2 = new Student("Neil", 202);

// → calls parent Constructor 1

5}
6}
How constructor chaining works in the
above code?
Student s1 = new Student("Athira", 25, 101);
Line num 3 in Runner class calls the Student constructor (String, int, int).
Inside it → super(name, age) is invoked (Line 23 in the Student class).
This triggers Parent Constructor 2 (String, int) (Line 12 in Person class).
"Athira", 25 are passed to parent.
After parent finishes, child constructor sets rollNo = 101.
Flow - Runner (line 3) → Student(String,int,int) → super(name, age) → Person(String,int)
Student s2 = new Student("Neil", 202);
Calls the Student constructor (String, int).
Inside it → super(name) is invoked (Line 30 in the Student class).
This triggers Parent Constructor 1 (String) (Line 5 in Person class).
Parent assigns name = "Neil" and gives default age = 18.
After parent finishes, child constructor sets rollNo = 202.
Flow - Runner → Student(String,int) → super(name) → Person(String)

Page 103 of 214


Java Complete Study Notes | By Jatin Sir

Summary
Constructor chaining is shown where Student(String,int,int) chains to Person(String,int) via
super(name, age) and Student(String,int) chains to Person(String) via super(name).
s1 → goes to Constructor 2 in parent because super(name, age) matches (String,int).
s2 → goes to Constructor 1 in parent because super(name) matches (String).
2 ways to do constructor chaining super & this !
super() → In Inheritance, super() is used, if we want to call parent class constructor from the
child class constructor.
this() → this keyword is used to do constructor chaining within the same class.
📌 Note: Note :
this (without parenthesis) → Refers to the current object’s instance variables, usually when local
variables or constructor parameters have the same name.
Example: [Link] = name;
Excecution - Class B
(Superclass/Parent)
& Class C
(Sub-class/Child)
------------------- [Link] ------------------1 package [Link];
------------------- [Link] ------------------1 package [Link];
2
2
3 public class B {
3 public class C extends B {
4 private int x;
4 private int z;
5 private int y;
5
6
6 public C(int x, int y, int z) {
7 public B(int x, int y) {
7
super(x, y); // call parent constructor
8
super(); // calls Object constructor
8
this.z = z;
9
this.x = x;

Page 104 of 214


Java Complete Study Notes | By Jatin Sir

9}
10
this.y = y;
10
11 }
11 @Override
12
12 public void add() {
13 public void add() {
13
[Link](getX() + z);
14
[Link](x + y);
14 }
15 }
15
16
16 // inherits getX(), setX() from B
17 public int getX() {
17
18
return x;
18 }
19 }
19
20
20
21 public void setX(int x) {
22
this.x = x;
23 }
24 }
}
Runner Class
1 package [Link];
2
3 public class Runner {
4 public static void main(String[] args) {

Page 105 of 214


Java Complete Study Notes | By Jatin Sir

5
B b = new B(10, 20);
6
[Link]();
7
8
C c = new C(10, 20, 30);
9
[Link]();
10 }
11 }
Excecution
Program execution begins from the main method inside the Runner class.
Line 4: Runner - Excecution happens in stack - main is loaded to mmry >> top points to main()
Line 5: B b = new B(10, 20); > Java excecutes RHS First
> object is created
> class is loaded into method area
> instance variables r created
> constructor is called
> obj B is created in heap mmry
> x & y - instance variables r created and initialized with default values
constructor is called and control goes to class B - Line 7
public B(int x,inty) - constructor's parameters x and y are local variables, created in stack
memory
x and y in stack get values 10 and 20
this.x = x
> Here value of local variable x is passed to instance variable x.
> value of local variable y is passed to instance variable y.
when the constructor finishes excecution - local variables r removed from stack n control goes to
main().
Now java excecutes LHS - B is assigned a hashcode and is pointed towards onject in heap
Next, control goes to class B - Line 13 - add ()
add() method is loaded in stack
> (1) java first checks - Is there a local variable x and y - No.
> (2) Then java checks - whether the class has instance variable x and y - yes
Java calculates x + y = 20
Now, control goes to Runner class > Line 8 > C c = new C(10, 20, 30) > Java excecutes RHS
first

Page 106 of 214


Java Complete Study Notes | By Jatin Sir

> object is created


> class is loaded into method area
> instance variables r created
> constructor is called
> obj C is created in heap mmry
> x, y and z - instance variables r created and initialized with default values
constructor is called and control goes to class C - Line 6 - parameterized constructor of C
Constructor is a method and it is excecuted in stack memory.
constructor's parameters x and y are local variables, created in stack memory
x,y and z are in stack get values 10 ,20 & 30.
this.x = x
> Here value of local variable x is passed to instance variable x.
> Value of local variable y is passed to instance variable y
> When the constructor finishes excecution - local variables r removed from stack n control
goes to main().
Now java excecutes LHS - C is assigned a hashcode and is pointed towards onject in heap.
Summary
Inheritance = relationship between similar entities
Use extends keyword to establish parent-child relationship
Only single & multilevel inheritance supported in Java
Multiple inheritance not supported → use interfaces
Constructor chaining ensures parent constructor always runs first
Child can access only non-private features of parent
Relationship between A,B & C using
Extends Keyword - Concept Check!
----------------- [Link] ------------------[Link]-----------1 package [Link];
package [Link];
2
2
------------------- [Link] ---------------1 package [Link];
2
-------1
3 public class A {
3 public class B extends A {
3 public class
C extends B {
4 protected int x;
4

Page 107 of 214


Java Complete Study Notes | By Jatin Sir

4 private int z;
5 protected int y;
5
5
6
6 public B(int x, int y) {
6 public C(int x, int
y, int z) {
7 public A(int x, int y) {
7
super(x, y);
7
super(x, y);

// call parent (B)

8
super();
8}
8
this.z = z;
9
this.x = x;
9
9}
10
this.y = y;
10 public void add() {
10
11 }
11
[Link](getX() + getY());
11
@Override
12
12 }
12 public void add() {
13 public int getX() {

Page 108 of 214


Java Complete Study Notes | By Jatin Sir

13
13.
[Link] (getX()getY(z);
14
return x;
14 public int getX() {
14
}
15 }
15
return [Link]();
15
16
16 }
16 public int getZ() {
17 public void setX(int x) {
17
17
return z;
18
this.x = x;
18 public void setX(int x) {
18 }
19 }
19
[Link](x);
19
20
20 }
20 public void setZ(int z)
{
21 public int getY() {
21
21
this.z = z;
22
return y;
22 public int getY() {

Page 109 of 214


Java Complete Study Notes | By Jatin Sir

22 }
23 }
23
return [Link]();
23 }
24
24 }
25 public void setY(int y) {
25
26
this.y = y;
26 public void setY(int y) {
27 }
27
[Link](y);
28
28 }
29 @Override
29
30 public String toString() {
30 @Override
31
return "A [x=" + x + ", y=" + y + "]"; 31 public String toString() {
32 }
32
return "B [x=" + getX() + ", y=" + getY() + "]";
33 }
Runner Class for A , B & C
1 public class ARunner {
public class CRunner {
2 public static void main(String[] args) {
public static void main(String[] args) {
3 A a = new A(10, 20);
C c = new C(50, 60, 70);
4 [Link](a);
[Link]();
5 [Link]([Link]());
[Link]([Link]())

Page 110 of 214


Java Complete Study Notes | By Jatin Sir

6 [Link]([Link]()); }
[Link](c);}
}
public class BRunner {
public static void main(String[] args) {
B b = new B(30, 40); // calls A(int,int) via super()
[Link]();

// prints ?

[Link](b); // calls [Link]()


}
}
}
Concept Check!
115. When we run new C(10, 20, 30), in what order do the constructors of A, B, and C
execute?
Why?
2. Why must B(int x, int y) call super(x, y)? What happens if we remove it?
116. Since x and y are private in class A, how can class B and class C still access them?
4. What happens if you remove super(x, y) from B’s constructor?
5. In A(int x, int y), why do we write this.x = x; instead of super.x = x;?
In which situations do we use this() and super() inside constructors?
117. Both B and C override add(). If we create C c = new C(1, 2, 3); [Link]();, which add()
executes, and why?
118. For [Link](c) where c is a C object, which toString() method is used?
What if C does not override toString()?
119. If z in C is private, can B access it directly? If not, how should B get its value?
120. How would you use this() to call one constructor of A from another constructor in the
same
class?
Static in Java Overview
Need to read from book
Let's Understand: What is a Design
Pattern and Why Do We Need It?
Design patterns are a toolkit of tried and tested solutions to common problems in software
design.
They also help apply Object-Oriented Programming (OOP) principles in a more structured and
scalable manner.

Page 111 of 214


Java Complete Study Notes | By Jatin Sir

Types Of Design Patterns!


| Type
| What it does
| Example Patterns
| Behavioral
| Deals with how objects communicate and behave | Observer, Strategy, Iterator
Where Does Builder Design Pattern
Fit?
The Builder Design Pattern is a creational design pattern.
It is used to build complex objects step by step, especially when there are many parameters or
optional fields.
Before We Dive In – Let’s Revisit: How
We Usually Pass Values — Using
Constructors?
A constructor is a special method that has the same name as the class.
It is used to initialize objects and pass values to instance variables at the time of object creation.
Typically, we pass all the required values (i.e., instance variables) directly into the constructor.
But what if a class has 10… 15… or even 25 fields? Passing all of them through a constructor
becomes hard to read and error-prone.
We'll end up writing multiple overloaded constructors with different combinations - this is called
the Telescoping Constructor Problem.
It becomes messy and hard to maintain.
So, What About Setters?
Why not create the object first and use setters to assign values?
Setters make the object mutable (values can change anytime).
It also turns object creation into a two-step process (not clean for required fields).
There's no guarantee that all mandatory fields are set before using the object.
So what's the Solution? That’s Where
Our Saviour Comes In — The Builder
Design Pattern!
Builder Design Pattern offers flexibility.
It avoids constructor telescoping (multiple overloaded constructors).
> Constructor telescoping happens when we create multiple constructors with different
combinations of parameters to handle various configurations of an object.
It improves code readability and maintainability.
What is a Builder Design Pattern?
The Builder Design Pattern is used to create objects step by step, when there are many fields
— especially when some fields are optional and some are mandatory.

Page 112 of 214


Java Complete Study Notes | By Jatin Sir

Instead of writing many constructors - We can :


> Build the object step-by-step.
> Set values using method calls.
> Finally, call .build() to get the object.
> It makes code cleaner, readable, and less confusing.
Why is it called Builder Design
Pattern?
Because, It literally "builds" the object step-by-step — like how a builder constructs a house.
We don’t dump everything into one messy constructor.
Instead, we call methods one by one to set values (like putting walls, windows, and paint).
Finally, we call .build() — and boom - we get a complete object.
So, since it BUILDS THE OBJECTS IN PARTS and then combines them into a final form — it's
called the BUILDER DESIGN PATTERN!
How builder design
pattern works?
public class SimpleBuilderForStudent { // Outer Class
private final String name; // Mandatory
private final int rollNumber;
private final String course;
private final Integer phoneNumber; // Non - Mandatory
}
Create an OUTER CLASS and declare the instance variables .
📌 Note: NOTE: Mark all INSTANCE VARIABLES as
(1) FINAL (one of the big reasons to use the Builder pattern in the first place)
(2) PRIVATE
| Modifier | Why We Use It
the object IMMUTABLE. |
Why instance variable is Final ?
When we declare instance variables as final > helps make our object immutable - they can be
assigned only once (usually in the constructor).
After the object is built, its values cannot be changed !
Immutability improves: (1) Thread safety (2) Reliability (3) Ease of debugging.
Why Use private instance variable?
1. Hides the variable from outside the class
So no one can change it directly
2. Keeps the data safe
Only the class (or builder) can control how values are set
Let's create Constructor - and see whom should we pass to

Page 113 of 214


Java Complete Study Notes | By Jatin Sir

the constructor!
In traditional constructors, we’d pass all the variables like - SimpleBuilderForStudent(String
name, int roll, String course, Integer phone)
But with the Builder Design Pattern, we do it differently!
Let's park it here - We will decide whom to pass to constructor - after meeting an important
person!
private SimpleBuilderForStudent(?????) // Constructor parked without passing anything for now.
Step 2: Create a static inner class &
Step 3: declare the same instance
variables as outer class
Static Inner Class - Create a STATIC INNER CLASS called - "Builder" inside our outer class.
The Builder holds all the data needed to build the object.
It uses the same variables as the outer class (but without final).
This inner Builder class acts as a data carrier.
Instead of passing each value separately to the outer class constructor > we pass the whole
Builder object — which contains all the necessary values.
So now we clearly understand whom we should pass to the constructor —It’s the Builder, not
the individual variables.
public static class Builder { // Static Inner Class
private String name;
private int rollNumber;
private int phoneNumber;
private String course;
}
Step 4: Create Setter Methods in
Builder - called Builder Methods!
The setter methods in the Builder class is used to assign values to the variables in the static
Builder class.
These values are stored temporarily and later used to create the final object when .build() is
called.

// Setter methods for rollNumber

public Builder setRollNumber(int rollNumber) { // Return type of the method setRollNumber Builder

// Since we're inside the static inner class Builder - This method

returns a Builder object.


Page 114 of 214


Java Complete Study Notes | By Jatin Sir

[Link] = rollNumber;

// [Link] → Refers to the instance variable of

the Builder class.

// rollNumber (on the right side) - is the method parameter (the

local variable passed to the setter).


return this;

// 'this' refers to the current Builder object

// ... more setters

}
One Important Thing to Note:
The RETURN TYPE of the setter method is Builder — but why?
Because we're inside the static inner class Builder, and this method needs to return the same
Builder object (i.e., this) to allow method chaining.
What do the builder methods do?

Page 115 of 214


Java Complete Study Notes | By Jatin Sir

Chapter 11: Exception Handling


try-catch-finally, Custom Exceptions, Hierarchy

Each method in the builder class returns the same builder object(this) , so we can chain one
call after another like a fluent sentence.
This is called method chaining.
Method Chaining : Builder -> set name -> return Builder -> set rollNumber > return Builder.
So now, the static inner class named Builder holds all the instance variables and their setter
methods.
Step 5: Create a Constructor in the
outer Class
Since the Builder class already holds all the required values through its instance variables and
setter methods,
we don’t need to pass each variable separately to the outer class constructor.
Instead, we pass the Builder object itself, and the outer class can access all the values from it to
initialize its own fields.
private SimpleBuilderForStudent(Builder builder) { // Constructor with builder object
Builder → The class name of the static inner class (used as the data type)
builder → The reference variable (holds the data when passed as a parameter)
Why the name Builder ? Can we give
any name to the static inner class?
Yes! Technically, We can name the static inner class anything we want. It's just a class.
But, Builder is the convention (not a rule) — and naming it "Builder" makes our code - (1) Easier
to read (2) Instantly recognizable to other's going through the code.
why the constructor takes Builder as a
parameter ?
private SimpleBuilderForStudent(Builder builder)
The parameter type of the constructor is Builder because that's the name of the static nested
class inside outer class - SimpleBuilderForStudent.
We pass a Builder object to this constructor so that we can access all the values that were set
using the Builder methods and use them to initialize the outer class fields.
Step 6: Add a build() Method in
Builder! What it does?
The build() method is written inside the Builder class — and it is the final step of the Builder
Design Pattern.
• Creates the final object of the outer class
• Finalizes the object construction process
• Takes the values stored in the Builder object

Page 116 of 214


Java Complete Study Notes | By Jatin Sir

• Passes them to the outer class via its constructor


• Returns the fully built object

// Build method to create final object

public SimpleBuilderForStudent build() {


return new SimpleBuilderForStudent(this); // Final object is created here

// This build() method is called at the end in the runner class, after all the setter
methods

are chained.
}
Step 7: Create a Runner Class and
Call the Builder
Why do we need a Runner class?
The Runner class is used to test and create objects using the Builder pattern.
It helps demonstrate how we can set values using method chaining and finally build the actual
object of the outer class.
What happens inside the Runner class?
We first create an object of the Builder class.
Then we use method chaining to set the required fields.
At the end, we call .build() — this is the step that creates the final object of the outer class.
SimpleBuilderForStudent student = new [Link]()
.setName("Athira")
.setRollNumber(101)
.setCourse("Java")
.build(); // Creates the final object
What does .build() do?
.build() is a method defined inside the static Builder class.
It uses new SimpleBuilderForStudent(this) to call the private constructor of the outer class.
It passes the current Builder object (this) to the constructor.
The constructor extracts all the values from the Builder object and initializes the outer class’s
fields.
This works because both the Builder class and the constructor exist inside the same outer class,
even if the constructor is private.
How to handle Optional Fields in Builder ?
In the Builder pattern, if a field is optional (like phoneNumber) - we simply don’t call its setter in
the Runner class.

Page 117 of 214


Java Complete Study Notes | By Jatin Sir

The field will take its default value (e.g., 0 for int, null for String).
Notes:
If we skip setPhoneNumber( ) >> it will stay as default 0.
If we skip setCourse() >> it will stay as null.
We don’t need any special logic — just don’t call the setter!
Do we need to write the setter method for an optional field?
Yes, we should write the setter — even if it's optional.
But why write it if we’re not always passing values?
Because the Builder Pattern gives users the choice to set only the fields they want. We’re not
forcing them — we’re just making the option available.
Even if the field is not always set, it’s part of the class design — and without the setter: The user
can’t set the value even if they want to and object becomes inflexible and incomplete.
Builder Design code with comments !
package builderdesignpatternpractice;
public class SimpleBuilderForStudent {

// Making instance variables final to ensure immutability after object creation

private final String name;

// Mandatory

private final int rollNumber; // Mandatory


private final int phoneNumber; // Optional
private final String course;

// Optional

// Step 5: Constructor of outer class accepts Builder object - Instead of passing each
field, we

pass the Builder object


private SimpleBuilderForStudent(Builder builder) {
[Link] = [Link];
[Link] = [Link];
[Link] = [Link];
[Link] = [Link];
}

Page 118 of 214


Java Complete Study Notes | By Jatin Sir

// Optional: toString method for printing object details

@Override
public String toString() {
return "SimpleBuilderForStudent{" +
"name='" + name + '\'' +
", rollNumber=" + rollNumber +
", phoneNumber=" + phoneNumber +
", course='" + course + '\'' +
'}';
}

// Step 2: Static Inner Builder Class

public static class Builder {

// Step 3: Declare same fields as outer class

private String name;


private int rollNumber;
private int phoneNumber;
private String course;

// Step 4: Create setter methods (method chaining enabled by returning 'this')

public Builder setName(String name) {


[Link] = name;
return this; // Allows method chaining
}
public Builder setRollNumber(int rollNumber) {
[Link] = rollNumber;
return this;
}

// Optional field: phoneNumber

public Builder setPhoneNumber(int phoneNumber) {


[Link] = phoneNumber;
return this;

Page 119 of 214


Java Complete Study Notes | By Jatin Sir

}
}
public Builder setCourse(String course) {
[Link] = course;
return this;
}

// Step 6: Build method to return the final object

public SimpleBuilderForStudent build() {


return new SimpleBuilderForStudent(this); // Pass builder to outer class constructor
}
}
}
Runner
package builderdesignpatternpractice;
public class StudentRunner {
public static void main(String[] args) {

// Step 7: Create Builder object and chain setters

SimpleBuilderForStudent student = new [Link]()


.setName("Athira")

// Mandatory

.setRollNumber(101)

// Mandatory

//.setPhoneNumber(123456789) // Optional: skipped


.setCourse("Java")

// mandatory

.build();

// Final object created

Page 120 of 214


Java Complete Study Notes | By Jatin Sir

// Print object content

[Link](student);
}
}
Exception Handling
Exception refers to an unwanted interruption that affects the normal flow of a program.
What is Exception Handling?
Exception Handling is finding ways to handle the unwanted interruptions.
We can handle this unwanted interruption caused by the risky code by giving proper error
messages and make the code robust and user friendly!
Why Exception Handling?
We write code assuming things will work perfectly. But what if something goes wrong?
Situations like:
(1) Reading a file – the file path may be wrong, or the file may not exist
(2) Connecting to a database – the DB might be down
(3) Accessing a null object – causes NullPointerException
(4) Accessing a missing element – causes ElementNotFound-type errors
These interruptions should be handled properly, else the program will crash.
Benefits of Exception Handling
Helps display proper error messages
Improves the user experience
Easier debugging — trace the exact line where the error occurred
Makes code robust and reliable
Hierarchy of Exception Classes
Object (Parent class)
[Link] package)
│ extends
Object is the parent of all classes in java (belongs to
┌────┴────┐
│Throwable│ ←
Throwable is the general class for all exceptions (belongs to
[Link])
extends
└───┬────-┘ extends
┌────────┴────────┐

Page 121 of 214


Java Complete Study Notes | By Jatin Sir

(class)Exception
Error (class)
Throwable is the parent class of both Exception and Error
Belongs to the [Link] package
Throwable has two child classes - Exception & Error
Exception → can be handled using try-catch
Error → cannot be handled (e.g., OutOfMemoryError)
Types of Exceptions
(1) Checked Exceptions and
(2) Unchecked Exceptions
Checked Exceptions
Checked by the compiler at compile time
Why Are Some Exceptions
"Checked"?
Exceptions like FileNotFoundException and SQLException are checked by the compiler
because:
There is a high chance that things can go wrong in these cases
These problems are often out of our control — and Java wants us to handle them properly
markdown
Since these are very common real-world risks that occur at runtime, Java wants us to prepare
for them in advance — during compilation.
If we don’t handle them - Java throws a compile-time error - These are known as Checked
Exceptions.
Unchecked Exceptions
Unchecked exceptions are RUNTIME Exceptions that are not checked by the compiler during
compilation.
• The program compiles successfully, but may fail at runtime.
• Java does not force you to handle them using try-catch or throws.
• These exceptions occur due to programming mistakes or memory-related issues, such as:
• Accessing null references → NullPointerException
• Dividing by zero → ArithmeticException
• Accessing invalid array indexes → ArrayIndexOutOfBoundsException
Explanation:
NullPointerException → when we try to use an object that is null
ArrayIndexOutOfBoundsException → when we access an array index that doesn't exist
ArithmeticException → when we perform illegal math (like 10 / 0)
Who is the Parent of Exception?
All exceptions inherit from Throwable, which in turn extends Object, the parent of all classes in
Java.

Page 122 of 214


Java Complete Study Notes | By Jatin Sir

How to Handle Exceptions in Java ?


The best way to handle exceptions in java is Using try-catch
block
try {

// We use `try-catch` to handle exceptions and stop the program from crashing

unexpectedly.

// Risky code that might catch an exception

} catch (ExceptionType refVar) {


[Link]([Link]());
[Link] StackTrace();

// Handling code

}
Different Types of Exceptions
(1) Arithematic Exception
ArithmeticException happens when you perform an illegal math operation in Java — most
commonly dividing a number by zero.
public class Main {

// Main class of the program

public static void main(String[] args) { // Entry point of the program


int a = 10, b = 0;
issue)
int result = 0;

// Two integer variables, 'b' is 0 (this will cause divide-by-zero

// Variable to store the division result

try {

// 'try' block → place risky code here

Page 123 of 214


Java Complete Study Notes | By Jatin Sir

result = a / b;

// This will cause ArithmeticException because dividing by 0 is not

allowed
} catch (ArithmeticException e) { // 'catch' block → runs if an ArithmeticException happens
[Link]("can't divide a number by zero!"); // Custom friendly message to user
[Link]([Link]()); // Shows Java's built-in short message (e.g., "/ by
zero")
[Link]();

// Prints the full stack trace (type, message, line number)

// This will still run because we handled the exception instead of letting the program
crash

[Link]("Result: " + result); // Prints '0' because division was not successful
[Link]("Hello");

// Just to show program continues

}
}
(2) ArrayIndexOutOfBoundsException
ArrayIndexOutOfBoundsException happens when we try to access an array index that does not
exist.
Java arrays have fixed sizes, so valid indexes are from 0 to length - 1.
public class Main {
public static void main(String[] args) {

// Creating an array of size 3 (valid indexes: 0, 1, 2)

int[] a = new int[3];

// Storing values in each index

a[0] = 10;
a[1] = 20;

Page 124 of 214


Java Complete Study Notes | By Jatin Sir

a[2] = 30;
try {

// Trying to store a value at index 3 (invalid, last valid index is 2)

a[3] = 40; // Will cause ArrayIndexOutOfBoundsException


} catch (ArrayIndexOutOfBoundsException e) {
[Link]("Array Index doesn't exist"); // Friendly message to the user
[Link]([Link]()); // Shows the exact error message (e.g., "Index 3 out
of bounds for length 3")
[Link]();

// Prints the full stack trace for debugging

// This line will still run because we handled the exception

[Link]("Hello");
}
}
3. NullPointerException
A NullPointerException occurs when a reference variable is not pointing to any object, but we try
to access its methods or properties.
public class Main {
public static void main(String[] args) {
Person p = null; // Reference variable 'p' is not pointing to any object
try {
[Link]([Link]()); // Trying to call a method on null →
NullPointerException
} catch (NullPointerException e) {
[Link]("Object is null!"); // Custom friendly message
[Link]([Link]()); // Shows Java's built-in message (usually null)
[Link]();

// Full stack trace (type, message, and line number)

}
[Link]("Program continues..."); // Proves program didn’t crash

Page 125 of 214


Java Complete Study Notes | By Jatin Sir

}
}
Practise Questions
[Link] Between Exception and
Error in Java ?
Exception
Represents conditions a program can recover from.
Can be caught and handled using try-catch.
Example:
FileNotFoundException → Ask user to choose another file.
SQLException → Retry database connection.
Error
Represents serious problems that are usually not recoverable.
Should not be caught and handled in most cases (though technically you can catch them, it’s
not recommended).
Examples:
OutOfMemoryError → Program ran out of heap space.
StackOverflowError → Infinite recursion.
2. Explain the difference in behavior
and exceptions between:
What happens if we try to access methods or properties on each of these variables?
String name = null; // Initialized with null
String name2;

// Declared but not initialized (local variable)

Case 1 – String name = null;


The code compiles.
The variable has been explicitly set to null, meaning it points to no object in memory.
If we try to call a method (e.g., [Link]()), Java will throw a NullPointerException at
runtime.
Case 2 – String name2;
The code will not compile if you try to use name2 before assigning a value.
Local variables in Java do not get default values.
Since it’s never initialized, the compiler gives an error before the program runs.
Therefore, no runtime exception occurs — the program can’t even start.
📌 Note: NOTE : If these variables were instance variables (declared at class level), both
would
automatically get a default value of null.

Page 126 of 214


Java Complete Study Notes | By Jatin Sir

In that case, calling a method on either would cause a NullPointerException at runtime.


3. What is the purpose of the finally
block?
finally is for code that must run no matter what — whether an exception happens or not.
Example: Closing a database connection even if a query failed.
4. How do you create a custom
exception?
Extend Exception (checked) or RuntimeException (unchecked) and throw it when a
specific business rule fails.

class AgeException extends Exception {


public AgeException(String msg) { super(msg); }
}

5. Is a try block always required before


a catch block?

Yes — catch must come after a try.


But a try can also be followed by a finally without a catch.

6. What types of exceptions are caught


during compile time?
Checked exceptions — compiler forces us to handle them.
Example: FileNotFoundException, SQLException.

7. What are best practices for


exception handling?
Catch only what we can handle → Don’t write a catch block if we can’t do anything
meaningful
to fix or respond to that exception.
Let it propagate to a higher level where it can be handled properly.
Log exceptions for debugging → Always log the full details ([Link]() or a
logging
framework) so root cause diagnosis is easy.
Show friendly messages to users → Never show technical error details to end users; use
simple, helpful text. Example: “Something went wrong. Please try again.”
Clean up resources → Always close files, database connections, or network sockets in a
finally
block or use try-with-resources to prevent resource leaks.

8. What are throw and throws, and


how do they differ?
throw → actually throws the exception object
throws → declares that a method might throw exceptions

Page 127 of 214


Java Complete Study Notes | By Jatin Sir

9. How do you handle an exception?


By wrapping risky code in a try-catch and providing alternate steps.
Example: If payment gateway is down, show “Try again later” instead of crashing.

10. How can we catch multiple


exceptions?
Either with : catch (IOException | SQLException e) { ... } // Java 7+
or multiple separate catch blocks.

11. Differences between checked and


unchecked exceptions?

Checked → compiler forces you to handle (IOException)


Unchecked → occurs at runtime, compiler doesn’t check (NullPointerException)

12. What is the difference between an


exception and an error?
Exception → recoverable (e.g., file not found)
Error → serious problem, not recoverable (e.g., OutOfMemoryError)

13. What is exception chaining?


Passing one exception as the cause of another.
Helps keep original error details for debugging.

14. What is a stack trace and how


does it help debug?
A detailed list showing where the exception happened in our code.
It includes class name, method, and line number.

15. Name the different types of


exceptions in Java.
Checked (compile-time) & Unchecked (runtime)

16. Can a try block exist without a


catch or finally?
No — it must be followed by either catch or finally (or both).

17. Difference between finally, final,


and finalize?
finally → cleanup code block
final → keyword to make variable constant, method non-overridable, class non-inheritable
finalize() was a method called by Garbage Collector before object destruction, but it’s
deprecated because cleanup should be done explicitly using try-with-resources or manual
close
methods."

18. What is try-with-resources?

Page 128 of 214


Java Complete Study Notes | By Jatin Sir

try-with-resources is a try statement in Java that automatically closes resources (like


files,
database connections, sockets) after the try block ends.
It works with any class that implements the AutoCloseable (or Closeable) interface, so we
don’t
have to close resources manually in a finally block.
try (FileReader fr = new FileReader("[Link]"))

19. Can multiple exceptions be caught


in one catch block?
Yes, using - catch (IOException | SQLException e)

20. Can you rethrow an exception?


Yes — rethrowing means catching an exception in one method and then throwing it again so
that it can be handled by another method higher up the call stack.
It’s often done when:
We want to log the exception or take some partial recovery steps,
But still let the caller method decide the final handling.

21. Why does an exception occur?


Because something unexpected happens in our code:

- File not found


- Database down
- Divide by zero
- Null reference access
These can be due to programming mistakes or external problems.

File Handling in Java


File handling means to read from, write to, create, delete
and manipulate contents of files programatically.

File handling allows Java programs to perform file I/O


(input-output) operations like:
- Creating files
- Checking if a file exists
- Deleting files
- Reading or writing file content

Packages for File Handling


Java provides two main packages:
● [Link] – I/O operations
● [Link] – new I/O operations

File Class in Java


File is a class in [Link] package.

Page 129 of 214


Java Complete Study Notes | By Jatin Sir

The File class in Java acts as a reference to a file or directory path on the system.
It helps us to interact with external files or directories — such as checking if they
exist,
creating new ones, deleting them, or retrieving their properties (like name, path, size).

How to create an object of file class ?


File file = new File("path/to/[Link]");

Path of the file should be SYSTEM INDEPENDENT.


For windows - path separator is a BACKWARD slash & For Mac, Linux & Unix - path
separator is FORWARD slash.
In Java, always prefer forward slash (/) — Java handles it internally.
Always use Relative path (file name) over Absolute path( starts from root).

File Handling Program in Java


1 package [Link];
2 import [Link];
3 import [Link];
4 import [Link];
5 public class FileRunner {

public static void main(String[] args){


// Creating a file object from file class to check existence

7
File file = new
File("/Users/athira/Documents/2025/Java_Project/Javaprograms_SDET/[Link]");
// Create new file - Creating a new file object to attempt file creation
8
File newfile = new
File("/Users/athira/Documents/2025/Java_Project/Javaprograms_SDET/[Link]");
9
10
11
12
13
14
15

try {
if([Link]()){
[Link]("File " + [Link]() + " created successfully");
}
else{
[Link]("Cannot create file - file already exists");
}
// // Handle any IOException during file creation

Page 130 of 214


Java Complete Study Notes | By Jatin Sir

16
} catch (IOException e) {
17
[Link]("Cannot create file " + [Link]() + ", something went
wrong");
18
[Link]();
19
}

20
21
22
23
24
25
26

27
28
29
30
31
32
33 }
34 }

// exists() - Check if the file exists


if([Link]()){
[Link]([Link]() + " file present");
[Link]("Path: " + [Link]());
}
else {
[Link]("File not present");
}
// delete() - To delete a file
if([Link]()){
[Link]([Link]() + " successfully deleted");
}
else{
[Link]("Cannot delete file");
}

Explanation of File Methods


exists()
The exists() method checks whether the file or directory referred to by the File object
exists on
the file system (i.e., in the specified path on the computer).
Line 20 → To check whether a file exists in the specified path on the computer.

Page 131 of 214


Java Complete Study Notes | By Jatin Sir

Return : TRUE if the file is present,


Return : FALSE if the file is not present.

getName()
Returns the file name along with its extension.
- Line 11 → To get the name of the newly created file.
- Line 17 → To show the name of the file when creation fails (inside `[Link]`).
- Line 21 → To get the name of an existing file.
- Line 28 → To confirm the name of the deleted file.

getAbsolutePath()
Returns the complete path of the file.
Line 22: Returns the complete path of the file, starting from the root directory.

createNewFile()

Creates a new physical file on the disk if it doesn't already exist.


Returns TRUE : If the file is created successfully.
Returns FALSE : If the file already exists or could not be created.
Line 8 → Creates a File object in memory (no file created yet — just a reference to the
path)
Line 12 → Actually attempts to create the file in the file system using createNewFile()
Tip: Always use createNewFile() inside a try-catch block to handle IOException.

delete()
Deletes the file from the file system.
Returns TRUE – If the file was deleted successfully
Returns FALSE – If the file could not be deleted (e.g., file doesn't exist or is in use)
Line 27 → Checks whether the file can be deleted using `[Link]()`
Line 28 → Prints confirmation if deleted
Line 31 → Prints error if deletion fails

Why we handle Exception in File


operation?
When working with files, there’s always a chance of
encountering unexpected issues like:
File not found
Permission/access restrictions

Corrupted or unreadable files


Disk or I/O failures
Since these are checked exceptions (i.e., compile-time exceptions), Java forces us to
handle them — or else the program won't compile.
That’s why it's essential to wrap file operations inside a try-catch block.

Try-Catch Block helps to:


(1) Prevent unwanted program interruptions.
(2) Provide user-friendly messages for failures.

Page 132 of 214


Java Complete Study Notes | By Jatin Sir

(3) Handle errors like missing files or restricted paths gracefully.


try {
// File operations like createNewFile(), read, write
} catch (IOException e) {
// Handle errors without crashing the application
}

Always assume file operations may fail — prepare our program to recover smoothly.

Methods to Check File Properties


1 package [Link];
2 import [Link];
3 import [Link];
4 public class FileRunner2 {

public static void main(String[] args) {

File myFile = new File("demo\\[Link]");

// Returns the name of the file with extension


[Link]([Link]());

// Returns the full absolute path of the file


[Link]([Link]());

// Checks if this path is a file


[Link]([Link]());

10

//Checks if this path is a directory (expected false here)


[Link]([Link]()); // false

11

//Checks if the file has read permission


[Link]("Can read?? " + [Link]());

Page 133 of 214


Java Complete Study Notes | By Jatin Sir

12

//Checks if the file has write permission


[Link]("Can Write?? " + [Link]());

13

//Checks if the file has execute permission


[Link]("Can Execute?? " + [Link]());

14

// Returns the parent directory path of the file


[Link]("Parent Folder: " + [Link]());

15

// Returns the size of the file in bytes


[Link]("Size of the file: " + [Link]()); // bytes

16
17

// Create a directory
File logDirectory = new File("logs");

18

// Makes a directory with the name 'logs' if it doesn't exist


[Link]();

19

// Confirms whether the directory was created


[Link]([Link]()); // true

20 }
21 }

Methods Used in This Program


getName() >> Line 7 - Returns the name of the file or directory.
getAbsolutePath() - Line 8 - Returns the full path to the file on the system.
isFile() - Line 9 - Checks if the given path is a file.
isDirectory() - Line 10 - Checks if the given path is a directory.
canRead() - Line 11 - Returns true if the file is readable.
canWrite() - Line 12 - Returns true if the file is writable.
canExecute() - Line 13 - Returns true if the file can be executed.
getParent() - Line 14 - Returns the name of the parent directory where the file resides.

Page 134 of 214


Java Complete Study Notes | By Jatin Sir

length() - Line 15 - Returns the size of the file in bytes.


Directory Creation - Line 18 - mkdir() - Creates a new directory named "logs" in the
current project location.
isDirectory() - Line 19 - Used to verify if the "logs" directory was successfully created.

Serialization & De - Serialization !


Let’s start with a simple example of creating an object in Java.
This will help us understand where the object lives in memory and why we eventually need
serialization ?
Contact contactPerson = new Contact("Java", "9876543210"); // This line creates an object
contactPerson .

Where is this Object Stored?


It is stored in heap memory, which is part of volatile memory (short term memory) in Java.

How Long Does It Stay There?


Only as long as the program is running.
Once the program ends, the JVM shuts down, and all memory (heap, stack, static) is cleared
by
the OS.
That’s why heap memory is called volatile memory.

Different Types of Memory !


| Memory Type
| Description
| Examples
|
|-----------------------|--------------------------------------- |---------------------|
| Volatile Memory. | Temporary, lost after program ends | Heap, Stack, Static |
| Persistent Memory | Long-term, survives after program ends | File, Database
|

So What If We Want to Save This


Object After the Program Ends?
We need to store the object in persistent memory, like a file or database - To do this, we
use
Serialization.

What is Serialization?
Serialization is the process of converting a Java object into a byte stream so that it can
be:

> Saved to a file (.ser)

> Sent over a network

Page 135 of 214


Java Complete Study Notes | By Jatin Sir

> Stored in a database

Why Use Serialization?


> To store Java objects permanently
> To send objects across a network
> To retrieve object data later
Example: In Instagram — our profile and data are saved permanently even after we close the
app - That’s persistent memory.

Requirements for Serialization


The class must implement the Serializable interface

What is Serializable interface?


The Serializable interface in Java is a marker interface from the [Link] package.
It has no methods — that’s why it’s called a marker interface.
It is used to indicate that a class can be serialized — i.e., its objects can be converted
into a
byte stream and saved to a file or sent over a network.
Add the transient keyword to variables that don’t need to be serialized — i.e., variables
that
should not be saved permanently in the .ser file.
When a class implements Serializable, all its non-transient, non-static fields are
included in the
serialized form.

The following class Contact implements Serializable:


package [Link];
import [Link];
// Class must implement Serializable
public class Contact implements Serializable {
private static final long serialVersionUID = 1L; // Add a serialVersionUID (recommended
for
version control)
private String name;
private String contactNumber;
// transient → this field won't be saved during serialization

private transient String emergencyContactNumber;


}

Important
>
If a class does not implement Serializable, and we try to serialize it, we'll get a
NotSerializableException.

Page 136 of 214


Java Complete Study Notes | By Jatin Sir

How we write java object into a .ser


File - Serialization!
FileOutputStream - Create FileOutputStream (fos) to open a file named [Link] to write
bytes into it.
ObjectOuputStream - Wrap the byte-level file stream (fos) so we can write entire Java
objects
into it.
Call writeObject () to perform serialization.

public class ContactRunner1 {


public static void main(String[] args) {
Contact contactPerson = new Contact("java", "9898989890", "1000000000");
// Object created in heap memory (volatile)
FileOutputStream fos; // declare outside try block
ObjectOutputStream oos;
try {
fos = new FileOutputStream("[Link]");

// Opens/creates a file named [Link] to write bytes into it


oos = new ObjectOutputStream(fos);
// Wraps the byte-level stream into object-level stream
// so we can write entire Java objects
[Link](contactPerson);
// Converts your object into byte stream and writes it into file
} catch (IOException e) {
[Link](); // Or rethrow exception
}
[Link](contactPerson);
// Prints object (via toString), not the serialized bytes
}
}

What is [Link]?
It is a file that stores the object data in binary format [ blob file – Binary Large Obj]
It is not human-readable
We can use Deserialization to get the object back from it later

Advantages of Serialization
Data Persistence: Information can be securely stored and can be reloaded at any time
without
the need for re-entry.
Automation: The process of saving and retrieving data becomes automated, reducing manual
intervention.
Error Reduction: By minimizing human input, the chances of errors in data entry are
significantly
reduced.

What is Deserialization?

Page 137 of 214


Java Complete Study Notes | By Jatin Sir

Deserialization is the reverse process Reading the byte stream and converting it back to
the original Java object.
We need to read the file(blob/stream file) and create object out of it. So we need
fileinput stream
for reading it

How we read java object from a .ser


file - Deserialization!
FileInputStream – Creates a stream to read bytes from a file.
ObjectInputStream – Wraps the FileInputStream and converts the byte stream back into a
Java
object (Deserialization).
readObject() – This method is used to perform deserialization.
readObject() returns a value of type `Object`, which is the most general type in Java.
Since we know the actual object stored in the file is a `Contact`, we need to cast it back
to
`Contact` using type casting.
This process is called TYPE CASTING, where we convert the generic `Object` type to a
specific
class type (`Contact` in this case), like this:
Contact data = (Contact) [Link]();

public class ContactRunner2 {


public static void main(String[] args){
FileInputStream fis;
ObjectInputStream ois;

try {
fis = new FileInputStream("[Link]"); // Opens the .ser file to read bytes
ois = new ObjectInputStream(fis);
// Converts byte stream back to Java object
Contact data = (Contact) [Link]();//
// Read the object from the file and convert it back into a Contact object
[Link](data);
// Prints the deserialized object
//It's called type casting because we're converting the object’s type from Object
(generic)
to Contact (specific) using a cast.
// Always close streams after use
[Link]();
[Link]();
} catch (IOException | ClassNotFoundException e) {
[Link](); // Handles both IO and class load failures
}

Final Takeaway
If we want to store Java objects permanently - use Serialization to save them to a .ser
file.
Deserialization to bring them back when needed.

Page 138 of 214


Java Complete Study Notes | By Jatin Sir

Serializable: Parent-Child Relationship


If the parent class implements Serializable, then all child classes automatically become
serializable.
If only the child class implements Serializable, but the parent does not, then - the
parent’s fields
will not be serialized.
During deserialization, the parent’s no-arg constructor will run to reinitialize those
parent fields
(since they weren’t saved).

Serialization &
Deserialization using
File!
Using the File class in serialization/deserialization gives extra control over file
handling
(existence, metadata, directories), unlike basic serialization which directly uses file
paths.

When and Why to Use the File Class


in Serialization?
- The `File` object is used to define the file path or name. It gives extra control to:
> Check if file exists
> Get file metadata
> Work with directories
We can then pass it to `FileOutputStream` for writing the byte stream.

Serialization using the File class

// Create Array of objects


Student[] studentArray = new Student[3];
studentArray[0] = s1;
for (Student s : studentArray) {
[Link](s);
}
// Using a File Object Before FileOutputStream
File serializedData = new File("[Link]");
FileOutputStream fos;
try {
fos = new FileOutputStream(serializedData); // Opens file using File object
ObjectOutputStream oos = new ObjectOutputStream(fos); // Wraps stream
[Link](studentArray);
// Serialize the array of objects
[Link]("Data is stored");
[Link]();
[Link]();
} catch (IOException e) {
[Link]();

Page 139 of 214


Java Complete Study Notes | By Jatin Sir

Deserialization using the File class


// Deserialize the student array from the file "[Link]"
File serializedData = new File("[Link]"); // Define the file to read from
FileInputStream fis; // Reads raw bytes from the file
ObjectInputStream ois; // Converts byte stream back into Java objects
Student[] data = null; // Will store the deserialized Student[] object
try {
fis = new FileInputStream(serializedData); // Open the file for reading
ois = new ObjectInputStream(fis);
// Wrap FileInputStream with ObjectInputStream
data = (Student[]) [Link]();
// Read the object and cast it to Student[]

// Print deserialized array content


for (Student s : data) {
[Link](s);
}
[Link]();
[Link]();
} catch (IOException | ClassNotFoundException e) {
[Link](); // Handles both IO and class-not-found exceptions
}

Note :
When we serialize an array (e.g., Student[]), the .ser file stores the entire array
object.
But when we deserialize, the method readObject() always returns a generic Object.
That’s why we must cast it back to the specific type.
Student[] data = (Student[]) [Link]();

Why Casting Is Needed?


readObject() returns Object (the most general type in Java).
The JVM doesn’t know at compile time that the stored object is a Student[].
By casting, we’re telling the compiler - I know this is actually a Student[], not just any
Object.

Concept Check!

What is Serialization in Java?


Serialization is the process of converting a Java object into a byte stream so that it can
be
saved to a file or transmitted over a network.

What is Deserialization in Java?


Deserialization is the process of converting a byte stream back into a Java object.

Page 140 of 214


Java Complete Study Notes | By Jatin Sir

Which interface must a class implement to be serializable?


[Link]

Does Serializable interface have any methods?


No, it's a MARKER INTERFACE (doesn’t have any methods)

How do you serialize an object in Java?


FileOutputStream fos = new FileOutputStream("[Link]");
ObjectOutputStream oos = new ObjectOutputStream(fos);
[Link](object);

How do you deserialize an object in Java?


FileInputStream fis = new FileInputStream("[Link]");

ObjectInputStream ois = new ObjectInputStream(fis);


MyClass obj = (MyClass) [Link]();

What is the role of serialVersionUID?


It is a unique identifier used during deserialization to verify that the sender and
receiver of a
serialized object have loaded classes for that object that are compatible.
private static final long serialVersionUID = 1L;

What happens if serialVersionUID is not declared?


JVM generates one at runtime, but changes in class structure (like adding/removing fields)
can
lead to InvalidClassException during deserialization.

Can a static variable be serialized?


No. Static variables belong to the class, not the object, so they are not part of the
serialized
object.

What if a parent class is not Serializable but the child is?


Parent class fields won’t be serialized. You must handle them manually in the child class

What happens if you try to deserialize an object without the


class being available?

A ClassNotFoundException will be thrown

Can you serialize an object that has a reference to another


object?
Yes, if the referred object is also Serializable. Otherwise, a NotSerializableException
will occur.

You mark a field as transient but want to store it manually.


How do you do that?

Page 141 of 214


Java Complete Study Notes | By Jatin Sir

Use custom writeObject() and readObject() methods to handle that field manually.

What will happen if you modify a class after serializing its


object, then try to deserialize it?
If serialVersionUID doesn’t match, we’ll get an InvalidClassException

Array of Objects
Let’s revisit Array!

Array
Array is a linear data structure, which store similar kind of data!
It stores multiple values of the same data type in contiguous memory locations.
It allows data access efficiently using an index.
Arrays are non-primitive. They are type safe.
int[] a = new int[3];
int is a primitive type.
Java creates an array of 3 int slots in heap memory.
The reference variable a is stored in the stack.
a[0] = 100; // adding values to array
a[1] = 101;
a[2] = 103;

Stack
Heap
---------------------------------------| a | ---> | [100] [101] [103]
|
----------------------------------------

What is Array of Objects ?


An array of objects is an array that stores references to many objects of the same class.
Instead of creating each object one by one, we can group them in a single array and manage
them together.
Array of objects is ideal for:
Students in a school → Student[]

Products in a cart → Product[]


Movies in a library → Movie[]
We can scale from 1 object to hundreds — all with the same logic.

How to Create Array Of Objects?


Step 1: Declare array of references
Person[] p = new Person[3]; // p = reference variable (lives in stack).
// Person = user-defined class (type of object the array can hold).
// new Person[3] → allocates an array of 3 references in the heap, each slot is
initialized to null.
// Here each memory location is going to act as reference variable
// 3 memory locations created in heap act as reference variable

Page 142 of 214


Java Complete Study Notes | By Jatin Sir

Stack
Heap
------------------------------------------------| p | ---> | [null] [null] [null]
|
-------------------------------------------------

Person is a user-defined class (non-primitive type).


Java creates an array of 3 null references in the heap.
The reference variable p is stored in the stack.

Step 2: Create and assign objects

p[0] = new Person("Joe", "S101", "A");


p[1] = new Person("Jack", "S102", "B");
p[2] = new Person("Jen", "S103", "C");

What Does This Mean?


Each element in the array p is a reference to a Person object:
p[0] → Person("Joe", "S101", "A")
p[1] → Person("Jack", "S102", "B")
p[2] → Person("Jen", "S103", "C")
Each one is a separate object in memory, but all are of type Person.
Stack
Heap
------------------------------------------------| p | ---> | [ref0] [ref1] [ref2]
|.
actual Person object in the heap.
------------------------------------------------|
|
|
v
v
v
Joe
Jack
Jen
(p[0]) (p[1]) (p[2])

Now, each reference in the array points to an

Using for-each Loop in Array of


Objects
Here, Person is the class type used for each element.
for (Person per : p) {
[Link](per);
}

Page 143 of 214


Java Complete Study Notes | By Jatin Sir

Revisit: for-each with Primitive Array !


int[] arr = new int[3];
for (int a : arr) {
[Link](a);
}

CONCEPT CHECK

1. What is an array of objects in Java?


An array of objects is an array that stores references to many objects of the same class.
Instead of creating each object one by one, we can group them in a single array and manage
them together.

2. How does memory allocation work


in an array of objects?
- The array of references is created in heap memory.
- Each object must be created separately using `new`.
- Until initialized, the references are `null`.

3. If you declare Person[] p = new


Person[3]; but don’t initialize with new what happens when you try to access
p[0]?
We’ll get a NULL POINTER EXCEPTION because the array only holds NULL references until
objects are assigned.

4. How do you iterate over an array of


objects?
Using for or for-each loop:
for (Person person : p) {
[Link]([Link]());
}

5. Can you sort an array of objects?


Yes - Using [Link]() along with: Comparable (natural ordering) or Comparator (custom
ordering)

6. Can an array of objects hold


different types?
No, All elements must be of the declared type or its subclasses.
Example: Animal[] can hold Dog and Cat objects (since both extend Animal).

7. What's the difference between


Person[] and ArrayList?

Array → Fixed size, cannot grow dynamically.


ArrayList → Resizable, provides more flexibility with dynamic data management.

Page 144 of 214


Java Complete Study Notes | By Jatin Sir

Collection
Java Collection Framework (JCF) Introduced in java 1.2
> Java Collection Framework (JCF) is a UNIFIED ARCHITECTURE that provides a set of
classes and interfaces to store, retrieve, manipulate, and communicate aggregate data
efficiently.
> It was designed to bring all commonly used data structures under one standardized
structure,
making them easier to use, manage, and extend.

┌────────────────────┐
| Iterable (interface)
└────────▲───────────┘

extends

┌────────────────────────┐
| Collection (interface) |
└───────▲────▲────▲──────┘
│ │ │
extends │ extends

┌──────────────── ┐ ┌───────────────┐
┌────────────────────────┐
| List (interface)| | Set (interface)| | Queue (interface)
|
└──────▲──────────┘ └──────▲─────────┘
└────────▲────────────── ┘




implements
implements
implements



┌────────────────────┐ ┌────────────────────┐
┌────────────────────────────┐
| ArrayList (class) | | HashSet (class) | | PriorityQueue (class)
|
|LinkedList (class) | | LinkedHashSet
| | ArrayDeque (class)
|
| Vector (class) | | TreeSet (class) | |
|
| Stack (class)

Page 145 of 214


Java Complete Study Notes | By Jatin Sir

| └────────────────────┘ | LinkedList (class)


└────────────────────┘
| (also implements Deque)
────────────────────────────┘

|
|

LinkedList implements List & Deque (double-ended queue)

Why was JCF Introduced?


Before JCF, Java had multiple unrelated classes (like Vector, Hashtable, etc.) for
handling collections.
Java unified these under one architecture in JCF.
> Provides standard interfaces (List, Set, Queue, Map).
> Includes utility methods for sorting, searching, and manipulation.
> Supports type safety through generics.

What Is Iterable?
Iterable <E> is the root interface in the collection hierarchy. It allows an object to be
traversed
(iterated) through a collection, enabling sequential access to its elements.
Enables traversal of elements using:

(1) iterator() method - To iterate through elements


(2) forEach() > Enhanced loop using lambda
(3) spliterator() – For parallel iteration

Interfaces in JCF
1. Collection
Extends Iterable
Common methods: add(), remove(), contains(), size(), isEmpty(), clear()

2. List
order of insertion is maintained.
Allows duplicates and nulls.
Access via index.
Implementations: ArrayList, LinkedList, Vector, Stack.

3. Set

No duplicates
No guaranteed order (depends on implementation)
Implementations: HashSet, LinkedHashSet, TreeSet

4. Queue
FIFO structure
Used for task scheduling, buffers

Page 146 of 214


Java Complete Study Notes | By Jatin Sir

Implementations: PriorityQueue, ArrayDeque, LinkedList

5. Map (not part of Collection


hierarchy)
Key-value pair storage
Implementations: HashMap, LinkedHashMap, TreeMap, Hashtable

Why Use Generics in Collections?


Generics ensures type safety - only allows elements of the specified type.

List<String> list = new ArrayList<>();


[Link]("Java");

// Allowed

[Link](123);

// Compile-time error

What If There Is No Generics?


Without generics, collections return Object, meaning we’ll need to manually type cast each
element.
This increases chances of runtime errors like ClassCastException.
Generics provide type safety and eliminate the need for casting.

List list = new ArrayList(); // Raw type (No generics)


[Link](100);
int num = (int) [Link](0); // Manual casting needed

Why Collections Can’t Store Primitives


?
Collections store OBJECTS, not primitive types(int,double).
Collections use wrapper classes (Integer, Double, Character, etc.) because collections
work
with objects and they require reference types.
Java provides wrapper classes for each primitive type, like:

Integer for int

Character for char

Double for double

Page 147 of 214


Java Complete Study Notes | By Jatin Sir

List<int> list = new ArrayList<>(); // Error - primitives not supported


List<Integer> list = new ArrayList<>(); // Wrapper class

How do classes in Java Collection


Framework implement methods from
interfaces?
Java uses interfaces (like List, Set, Queue) to define what a class must do, and concrete
classes (like ArrayList, HashSet, LinkedList) to actually do it.
Interfaces declare abstract methods (method signatures only, no logic).
Concrete classes implement these interfaces and provide the actual logic for those
methods.
This promotes loose coupling and flexibility in how we work with collections.

Role of Polymorphism:
This is runtime polymorphism in action — where a parent reference (interface) points to
a child object (class) and calls overridden methods.

List<String> list = new ArrayList<>();

[Link]("Hello"); // List defines it, ArrayList implements it


Though list is of type List, the add() method that gets executed is from ArrayList.

Java Collection Hierarchy

Summary: Java Collection Hierarchy


Iterable is the top-most interface in the Collection hierarchy.
It defines the iterator() method and is implemented by all collection classes.
Enables use of the enhanced for-each loop (for-each) in Java.
Collection extends Iterable and is the root interface for most data structures (excluding
Map).
Collection has 3 main subinterfaces:
> List – Ordered, allows duplicates (e.g., ArrayList, LinkedList)
> Set – Unordered, no duplicates (e.g., HashSet, TreeSet)
> Queue – Typically FIFO (e.g., PriorityQueue, Deque)
Map is not a child of Collection; it's a separate interface that stores key-value pairs.
Common classes: HashMap, TreeMap, LinkedHashMap

Legacy Classes:
Vector, Stack, and Hashtable were introduced before Java 1.2
Synchronized but less preferred in modern development

Page 148 of 214


Java Complete Study Notes | By Jatin Sir

Chapter 12: Collections Framework


ArrayList, LinkedList, HashSet, HashMap, Iterators

Modern Alternatives:
Use ArrayList instead of Vector
Use Deque instead of Stack
Use ConcurrentHashMap instead of Hashtable for multithreaded use.
Collection - Brain Teasers!
Q1: What’s the difference between Collection and
Collections?
| Collection
| Collections
Q2: How is Uniqueness Maintained in HashSet and
HashMap?
Where did we study hashCode() + equals()?
We studied this in the context of both HashSet and HashMap, because:
Both use HASHING to store data
Both rely on hashCode() and equals() to check for uniqueness
> HashSet:
• Internally uses a HashMap where each element is added as a key.
• [Link]("apple") → becomes → [Link]("apple", PRESENT)
> Before inserting:
• First checks the element’s hashCode() to find the bucket
• Then uses equals() to ensure it’s not a duplicate
> HashMap:
• Keys are unique.
If two keys have the same hashCode(), it uses equals() to resolve collisions.
Duplicate keys overwrite the old value.
Q3: How does HashMap handle collisions?
WWhen two keys have the same hash index, Java creates a LinkedList inside that bucket to
store both entries.
Each new node is added to that list — this is how HashMap handles collisions.
[Link](16, "Java");
[Link](32, "Python"); // if both map to index 0 (16%16 = 0, 32%16 = 0)
Q4: What is the default initial capacity of a HashMap?
16 buckets (0 to 15)
And the load factor is 0.75 → so it resizes when it's 75% full.
Q5. What is the default initial capacity of an ArrayList?

Page 149 of 214


Java Complete Study Notes | By Jatin Sir

10 elements
When full, it increases capacity by 50%
new capacity = old capacity + (old capacity / 2)
Q5. Which data structure maintains insertion order? Which
doesn’t?

Maintains Insertion Order Does NOT Maintain Order

Q6. Difference between HashMap, TreeMap, and


LinkedHashMap ?
Q7. What happens if you store the same key twice in a
Map?
The value is overwritten.
[Link](1, "Java");
[Link](1, "Python"); // replaces previous value
Now [Link](1) will return "Python".
Q8. Is ArrayList thread-safe? What about Vector?
Q9. What is ConcurrentModificationException?
ConcurrentModificationException occurs when a collection is modified while being iterated using
something like a for-each loop.
Use Iterator with .remove() or CopyOnWriteArrayList to avoid this.
Q10. What is the difference between List and ArrayList?
List is an interface.
ArrayList is a class that implements List.
Q11. Difference between ArrayList and
LinkedList?
12. Which is faster – ArrayList or LinkedList?
For searching, ArrayList is faster.
For inserting/deleting, LinkedList is better.
Q13. Can we store null in ArrayList or LinkedList?
Yes, both allow multiple null values.
Q14. How to convert List to ArrayList?
List<String> list = new ArrayList<>();
ArrayList<String> arrayList = new ArrayList<>(list);
Q15. Can we convert Array to List?
String[] arr = {"a", "b"};
List<String> list = [Link](arr);
Q16: What is the difference between HashSet and

Page 150 of 214


Java Complete Study Notes | By Jatin Sir

LinkedHashSet?
Q17: Does Set allow duplicates?
No. Set maintains uniqueness using hashCode() and equals().
Q18. Can Set contain null?
HashSet allows one null value.
Q19. How do different Set and Map types handle null?
Q20 How many null keys and values can a HashMap have?
Q21: Difference between HashMap and LinkedHashMap?
Q22. What happens if you insert a duplicate key into a
HashMap?
The new value replaces the old one associated with that key.
Q23. Difference between keySet() and entrySet()?
keySet() returns only keys.
entrySet() returns key-value pairs.
Q24. Convert Set to List?
Set<String> set = new HashSet<>();
List<String> list = new ArrayList<>(set);
Q25. Convert Map keys to List?
List<String> keys = new ArrayList<>([Link]());
Q26. Convert Map values to List?
List<String> values = new ArrayList<>([Link]());
Q27. What is Iterable in Java?
It’s the root interface for all collection classes that can be looped using for-each.
It provides the method: Iterator<T> iterator();
All classes like List, Set, Queue implement Iterable.
Q28. What is the difference between Iterable and Iterator?
| Feature
| Iterable
| Iterator
Q29. How to use Iterator to loop through a List?
List<String> names = new ArrayList<>();
Iterator<String> it = [Link]();
while ([Link]()) {
[Link]([Link]());
}
Q30. What happens if you modify a List while iterating?
why?
ConcurrentModificationException is thrown.

Page 151 of 214


Java Complete Study Notes | By Jatin Sir

Java’s iterators are fail-fast. That means: If the structure of the list changes while we're iterating
over it, the iterator detects it and fails
immediately to prevent unpredictable behavior.
Q31. How to safely remove elements during iteration ?
Iterator<String> it = [Link]();
while ([Link]()) {
String val = [Link]();
if ([Link]("apple")) { // "apple" is the target value to delete
[Link](); // Safe removal
}
}
Q32. Does Iterator work on Arrays?
No. Arrays do not implement Iterable.
Use traditional for loop or [Link](array) to convert and iterate.
Q33. Is there a difference between iterate() and iterator() in
Java?
| Method
| Is it Exist? | Belongs To
| Purpose
| iterator() | Yes
| iterate() | Yes
collections |
| Iterable
Every class that implements Iterable (like List, Set) must override iterator().
iterate() – Not a valid method in core Java Collections.
[Link]() - exists in Java 8 - used to generate a stream of elements.
Q.34. What are the key methods in the Iterator interface?
Q35. What are the methods of the Iterable interface?
Q36. What is the relationship between Iterable and Iterator
interfaces?
ArrayList
Imagine we are building a Contact App with 100s of contacts.
Can we use an Array?
No — because:
Arrays have a fixed size, which must be declared at the time of creation.
In a contact app, we’ll frequently add or remove contacts, and we don’t know the total
number in advance.
So, arrays are not suitable for such dynamic operations.

Page 152 of 214


Java Complete Study Notes | By Jatin Sir

Why use ArrayList?



ArrayList is a resizable array (dynamic), meaning it can grow or shrink in size.

It stores elements in a contiguous memory structure, allowing fast access.
Features of ArrayList !
• Belongs to: [Link] package.
• Dynamic array → Resizable (unlike regular arrays).
• Allows duplicate values.
• Allows null elements.
• Maintains insertion order.
• Not synchronized (not thread-safe), but fast for single-threaded applications.
• Faster than Vector in single-threaded environments.
• Time complexity for accessing an element: O(1) → Constant Time
Why Do We Need ArrayList When We
Already Have Arrays?
Arrays are one of the oldest and simplest data structures in Java.
They help us store data in a contiguous memory block with index-based access — fast
and efficient!
But they come with a major limitation: Once the size of an array is defined, it cannot be
changed.
Imagine We're building a contact list or a shopping cart — and we don’t know how many
items will be added. Arrays will fall short here. This is where ArrayList comes in.
ArrayList – A Resizable Array!
ArrayList offers a dynamic way to store and manage data.
We don't have to worry about size — it can grow as needed.
Syntax of ArrayList
List<Integer> al = new ArrayList<Integer>();
>
List <Integer> : This defines a list that will store Integer objects — not primitive int, but its
object form, which is called a wrapper class.
>
al: This is the reference variable
>
new ArrayList<>() - This creates the object in heap memory
>
When this object is created:
> The ArrayList class is loaded into memory.
> Instance variables are created inside heap.

Page 153 of 214


Java Complete Study Notes | By Jatin Sir

> The constructor is called.


How Memory Works with ArrayList?
List<Integer> al = new ArrayList<Integer>();
What happens Internally ?

> al is created in the stack.

> It points to the memory allocated inside the heap.

> By default, ArrayList creates 10 memory slots (capacity) in the heap to store objects.

> Each slot can hold one Integer object.

> When we start adding elements -

> Elements are stored at sequential indexes, starting from index 0.

> With each addition, the size of the ArrayList increases.

> The internal capacity is fixed at 10 by default.

> Capacity remains unchanged until the ArrayList is full.


Adding Elements in ArrayList — How
Capacity and Size Work Internally ?
[Link](1); // Index 0 → Size = 1 → Capacity remaining = 9
[Link](2); // Index 1 → Size = 2 → Capacity remaining = 8
[Link](3); // Index 2 → Size = 3 → Capacity remaining = 7
[Link](4); // Index 3 → Size = 4 → Capacity remaining = 6
What Happens When ArrayList Gets
Full?
Once all 10 slots are filled, ArrayList automatically increases
its capacity.
To calculate new capacity :
newCapacity = oldCapacity + (oldCapacity / 2).
newCapacity = 10 + (10 / 2) = 15
> A new internal array with capacity 15 is created.
> All 10 existing elements are copied into this new array.
> The reference variable al now points to the new memory.
> The old array is removed by the Garbage Collector.

Page 154 of 214


Java Complete Study Notes | By Jatin Sir

> This resizing happens behind the scenes — giving you the power of a flexible array without
the manual effort!
Why Is ArrayList Fast? What is the
Time Complexity ?
Time complexity describes how the performance of an operation scales with the size of the
input.
ArrayList works like a normal array — all elements are stored next to each other in memory.
So when we say get(3), Java knows exactly where the 3rd element is.
It jumps directly to that spot — no searching, no looping.
This direct access makes retrieval very fast, even for large lists — and this happens in
CONSTANT TIME, i.e., O(1).
Time Complexity of ArrayList is O(1).
How to Make an ArrayList Thread-Safe
(Synchronized)?
2 ways - (1) By Using [Link]() & (2)
Using CopyOnWriteArrayList
(1) By Using [Link]()
By using collections utility method synchronizedList and pass the arraylist
List<String> syncList = [Link](new ArrayList<>());

// This ensures thread-safe access.

2. Using CopyOnWriteArrayList (Expensive Solution)


CopyOnWriteArrayList<String> safeList = new CopyOnWriteArrayList<>());
This is a thread-safe variant of ArrayList. It creates a fresh copy of the array list on
every write (add/remove/update), ensuring safe iteration during concurrent
modifications.
Expensive Solution – as it creates new copy everytime.
_ArrayList_BrainTeasers
ArrayList - Concept Review: How
Much Do You Remember?
Q1. What is the default capacity of an ArrayList in Java?
• 10
Q2. How does an ArrayList grow when the capacity is full?
• It increases by 50% of its current capacity.
• Formula: new capacity = old + (old / 2)
Q3. What is the difference between size() and capacity in an
ArrayList?
• size() = number of elements added

Page 155 of 214


Java Complete Study Notes | By Jatin Sir

• capacity = number of elements the internal array can hold


Q4. Where is an ArrayList stored in memory?
• The reference (e.g., al) is stored in the stack
• The actual data is stored in the heap
Q5. What happens when an ArrayList is full and a new
element is added?
• A new internal array is created with increased capacity,
old elements are copied into it, and the reference is updated.
Q6. Is ArrayList thread-safe?
• No. It is not synchronized by default.
Q7. How to make an ArrayList thread-safe?
• Use [Link](list) or CopyOnWriteArrayList<>
Q8. What is the drawback of CopyOnWriteArrayList?
• It is expensive — creates a new copy on every write operation.
Q9. Can an ArrayList hold primitive types like int?
• No. It can only hold objects like Integer (wrapper class).
Q10. What will happen if you try to access an index greater
than size?
• IndexOutOfBoundsException
Q11. How to remove all elements from an ArrayList?
• Use clear ()
Q12. Can ArrayList store null values?
• Yes, multiple null`s are allowed
Q13. Does ArrayList maintain insertion order?
• Yes
Q14. How do you sort an ArrayList?
• [Link](list) for natural order
• [Link](Comparator) for custom order
Q15. Difference between remove(int) and remove(Object)?
• remove(index) removes at given index
• remove(object) removes first occurrence of that object
Q16. What does contains() vs indexOf() do?
• contains(obj) returns true/false
• indexOf(obj) returns index or -1 if not found.
Q17. Can we clone an ArrayList?
• Yes, using .clone() — it performs a shallow copy
Q18. How to make a read-only ArrayList?
• [Link](list)
Q19. Is ArrayList fail-fast or fail-safe?

Page 156 of 214


Java Complete Study Notes | By Jatin Sir

• Fail-fast — throws ConcurrentModificationException if modified while iterating.


Q20. How does ArrayList differ from array in memory
management?
• Arrays are fixed-size; ArrayList grows dynamically & manages internal memory.
Q21. Can we manually set the capacity of an ArrayList?**
• Yes, using new ArrayList<>(initialCapacity)
Linked List
What is a LinkedList?
A LinkedList is a linear data structure where elements are stored in the form of nodes.
These nodes are connected like a chain — each node holds a reference (pointer) to the
next node. Unlike ArrayList, the nodes in a LinkedList are stored in scattered memory
locations, not in a continuous block.
The last node doesn’t point to anything — its pointer is set to null, marking the end of
the list.
We use LinkedList when we need frequent insertions and deletions, especially in the
middle of the list, because shifting is not required like in arrays.
Each node contains:
1. A value (the data)
2. A reference (or pointer) to the next node in the list.
What is a Node?
Node → [ Data | Reference to Next Node ]
Nodes are connected one after another using the references — like a chain scattered across
the memory, not continuous like in Array/ArrayList.
What Does a LinkedList Look Like
Internally?
Why Is the Last Node’s Reference
null?
In a LinkedList, each node has a reference (pointer) to the next node.
But for the last node >>> There is no next node after this.
So the reference is set to null — meaning >> This pointer is not pointing to any object in
memory.
Why Use LinkedList When We Already
Have Array and ArrayList?
Let’s understand it like a story:
We started with Arrays — but they come up with a limitation: Arrays have a fixed size. Once
created, we can’t resize them.
To overcome that, Java gave us: ArrayList — A resizable array that can grow and shrink
automatically.

Page 157 of 214


Java Complete Study Notes | By Jatin Sir

But ArrayList has another drawback: It stores data in contiguous memory locations.
So when we do frequent insertions or deletions (especially in the middle), it becomes slow due
to shifting of elements.
So, What’s the Solution ? LinkedList !
LinkedList is a data structure where nodes are not stored together in memory. Each node just
knows where the next node is.
Why LinkedList Works Better for Certain Scenarios ?
1. Insertion and deletion are faster (no shifting!)
121. It works well even if memory is fragmented (no need for big continuous blocks)
3. Nodes are connected using references, not physical positions
4. Supports bi-directional traversal if it's a Doubly Linked List
What is Time Complexity ?
Time Complexity is a way to measure how efficient a data structure is, based on how the
performance changes when you give it more data to handle.
What is the Time Complexity of linkedList and Why?
Time Complexity of LinkedList is O(1) - Constant Time, when we have a direct reference to the
node or its predecessor.
Operation takes roughly the same amount of time no matter how big the list [Link], Even if the list
gets bigger, Time complexity remains same as O(1), with no extra time
Time Complexity of LinkedList is O(N) - Linear Time, when accessing an element by index or
Searching for an element by value .
Why O(1)?
In a LinkedList
• nodes are NOT stored in continuous memory.
• To insert or delete, we just update the next (and maybe prev) pointers to skip or connect
around the node.
• This pointer adjustment takes **constant time — O(1).
Before deletion:
[10] → [20] → [30]
After deleting 20:
[10] ─────────→ [30]
No shifting. No resizing. Just a simple reference change.
In an ArrayList
• If we want to insert or delete an element from the middle:
• we have to shift all the other elements to fill the gap or make space — which takes O(n)
time.
• This makes the operation O(n) in the worst case.
Singly LinkedList
The reference in each node allows traversal in only one direction (Single direction) —

Page 158 of 214


Java Complete Study Notes | By Jatin Sir

from the first node (head) to the last node - forward movement.
We can’t go backward because nodes don’t store a reference to the previous node.
Doubly Linked List
In a Doubly Linked List, each node contains references to both the previous and the
next node.
This allows traversal in both directions (bi-directional traversing):
(1) Forward (head → tail)
(2) Backward (tail → head)
Bi-directional traversing makes traversal more efficient compared to a singly linked list.
📌 Note: NOTE :Java's LinkedList class uses Doubly Linked List
structure internally.
┌──────┬────┬──────┐
│ null │ 10 │ 666 │ ─────
└──────┴────┴──────┘

Prev D next



| 777 (address) ┌──────┬────┬──────┐
│ 777 │ 11 │ null │ last node
└──────┴────┴──────┘
Prev D next

666 (address)
This is the head → No previous node, so Prev = null
Node 1
777 is the memory address of the first node.
Address of previous Node is null because no previous node exists(this is the head)
666 is the pointer to the next node.
Node 2
777 is the address of the previous node (Node 1). It allows backward movement.
11 is the actual data stored.
null in the next field as there is no node after this → so this is the last node (tail).
Circular LinkedList
In a circular linked list, each node stores: Data + reference (pointer) to the next node.
The last node does not point to null, Instead, it points back to the first node.
This creates a continuous loop where, we can keep traversing from one node to the

Page 159 of 214


Java Complete Study Notes | By Jatin Sir

next and eventually we will come back to the starting node.


That’s why it's called a “circular” linked list — the nodes form a closed circle.
+--------------------------------+
V
777 --> +-------+-----------+
666 --> +-------+-----------+
| Data | Reference | --->

Data Reference

+-------+-----------+
+-------+-----------+

9 666
10 555

+-------+-----------+
+-------+-----------+
^
V
555 --> +-------+-----------+
+-------+-----------+
+--------------------------------- | 11 | 777 |
+-------+-----------+
Key Notes
● ArrayList provides fast access and update, but is slower for deletions due to
shifting.
● LinkedList excels in insertion and deletion, especially when done at the head or
tail.
Frequently Asked in Interviews
How to reverse a LinkedList ?
Why do we use linkedlist for manipulation and not ArrayList?
When it comes to frequent insertions and deletions, especially in the middle or beginning,
LinkedList outperforms ArrayList due to its internal structure.
##
✅ Key Reason:
• LinkedList uses nodes with pointers — allowing quick changes without shifting
elements.

Page 160 of 214


Java Complete Study Notes | By Jatin Sir

• ArrayList uses a contiguous array — making insertion/deletion expensive because


elements need to be moved.
--##
📊 Performance Comparison
| Operation
| LinkedList
ArrayList
----------------------------------------------------------------------- | ------------------------------------------------ |
Efficient → Just re-link pointers
• O(1) (if position is known) |
Slow → Needs shifting of elements → O(n) |
| Memory Layout
| Elements are not stored in contiguous memory
blocks


--##
💡 Example

// Insert at the beginning


[Link]("new"); //
[Link](0, "new"); //

✅ Very fast — no shifting needed


❌ Slow — shifts all elements right

Need a quick refresher on Interface & Inheritance? Click here to revise !

How we define and initialize a


LinkedList in Java ?

How LinkedList is Connected to List


and Deque Interfaces ?
LinkedList is a class which implements both - (1) List
interface (2) Deque interface (double-ended queue).
> Deque extends Queue, so LinkedList indirectly supports Queue methods too, So
LinkedList can behave like a List, Queue, and Deque.

Why do we say LinkedList implements


List and Deque, and not Queue?
Because in the Java Collections Framework - LinkedList directly implements: List &

Page 161 of 214


Java Complete Study Notes | By Jatin Sir

Deque.
public class LinkedList<E> implements List<E>, Deque<E>
> LinkedList is a class that follow the rules of both List and Deque interfaces.
> That means LinkedList must provide implementations for all the methods declared in both
interfaces.
> Since Deque extends Queue, LinkedList also inherits all the behaviors of a Queue.

How does Queue fit ?


LinkedList indirectly supports Queue behavior, But it doesn’t directly implements Queue
— instead, it implements Deque, which extends Queue.
Queue is a parent

Deque is a child of Queue


LinkedList implements the child (Deque), so it automatically gets the parent's behavior
(Queue).
┌───────────────┐
│ Queue (I) │
└──────▲────────┘

extends

┌──────┴───────┐
│ Deque (I) │
└──────▲───────┘

implements

┌──────┴────────────┐
│ LinkedList (class)│
└───────────────────┘

When & Why We Use List as the


Reference Type ?
In OOPs, we learnt that the reference type should be the
parent, and the object should be the child — this is known
as upcasting or runtime polymorphism.
List<String> namesList = new LinkedList<>();


Parent
Child's Object
(Reference Type)

// polymorphism or upcasting

1. List is the parent interface, and LinkedList is the child class that implements it.
2. Because of polymorphism (upcasting), we can easily switch between different
List implementations like ArrayList, Vector, LinkedList, etc., without rewriting our

Page 162 of 214


Java Complete Study Notes | By Jatin Sir

code.
3. This approach is great for flexibility.
4. Our code becomes more reusable and follows good design principles.
> List<String> namesList = new LinkedList<>();
> List<String> namesList = new ArrayList<>();

Limitations of Using List as the


Reference Type When Accessing Both
List & Deque Methods ?

When we want to use methods that belong specifically to the LinkedList class and the
Deque interface, if we use List as parent type
(1) We can only access methods defined in the List interface.
(2) We cannot access methods that are specific to LinkedList and Deque.
(3) Even though the object is a LinkedList, Java limits method access based on the
reference type — in this case, the parent interface List.
LinkedList<String> namesList = new LinkedList<>();
This gives us full access to all methods of List, Deque, and LinkedList.
List<String> namesList = new LinkedList<>();
This gives us access to only the methods defined in the List interface,as Java limits
access
based on the reference type (List, in this case — the parent interface).

Adding Elements to LinkedList


LinkedList is implemented as a Doubly Linked List, meaning each node holds
references to both its previous and next nodes, allowing traversal in both forward and
backward directions.
LinkedList maintains order of insertion.
LinkedList supports duplicates and allows null values.
LinkedList<String> namesList = new LinkedList<String>();
[Link]("python");
[Link]("java");
[Link]("postman");

[Link]("java");// Duplicates allowed


[Link](null);// Null is allowed in LinkedList
ArrayList<String> al = new ArrayList<>()
[Link]("JMeter");// ArrayList and LinkedList are using the SAME add() method from the List
interface.
[Link]("cypress");

How Elements Look in Memory


(Doubly Linked List)
Not sure how a Doubly Linked List works? [Click here to understand how it works]

Inserting Elements to a particular index


in LinkedList

Page 163 of 214


Java Complete Study Notes | By Jatin Sir

> Insertion in a LinkedList is fast because elements are inserted by simply updating the
links (pointers) between nodes, without shifting other elements as in an ArrayList.
[Link](1, "javascript"); // Inserting the element at INDEX 1

**The node that was previously at index 1 (address 002) moved to index 2, and all the
following
nodes were pushed forward.**
Address: 001
┌────────┬────────────┬────────┐
INDEX 0
│ Prev │ Data │ Next │
│ null │ python │ 005 │
└────────┴────────────┴────────┘




Address: 005
┌────────┬────────────┬────────┐
INDEX 1
│ Prev │ Data │ Next │
│ 001 │ javascript │ 002 │
└────────┴────────────┴────────┘




Address: 002
┌────────┬──────────┬────────┐
INDEX 2
│ Prev │ Data │ Next │
│ 005 │ java │ 003 │
└────────┴──────────┴────────┘




Address: 003
┌────────┬──────────┬────────┐
INDEX 3
│ Prev │ Data │ Next │
│ 002 │ postman │ 004 │
└────────┴──────────┴────────┘




Address: 004
┌────────┬──────────┬────────┐

Page 164 of 214


Java Complete Study Notes | By Jatin Sir

INDEX 4
│ Prev │ Data │ Next │
│ 003 │ java │ 111 │
└────────┴──────────┴────────┘

Remove an Element From LinkedList


(1) remove()
➤ Removes the head (first element) and returns it
(2) remove(int index) ➤ Removes the element at the specified index and returns it

(3) remove(object)

➤ Removes the first occurence of the object.

// (1) Removes the head (first element) and returns it


String data = [Link]();
[Link](data); // Output: python

// (2) Removes the element at index 1 and returns it


String data1 = [Link](1);
[Link](data1); // Output: javascript

// (3) Removes the first occurrence of the object "java" - returns boolean - indicating
whether the
object was found and removed!
boolean data2 = [Link]("java");
[Link](data2); // Output: true

Note:
Collections store objects, not primitive type.
Java Collections use Generics, which only work with objects — not primitive types. So,
we use wrapper classes like Integer, Double, Character, etc., instead of int, double, or
char.
Revisit Wrapper Classes ➜](../19_Wrapper_Class/[Link])
remove(Object o) returns a boolean, indicating whether the object was found and
removed.

get(), set() and contains() Methods!


(1) get(int index)
➤ Retrieves the element at the specified index
(2) set(int index, val) ➤ Updates the element at the specified index with a new value
(3) contains(object) ➤ Returns true (boolean), if the specified element exists in the list

(1) get() - Retrieve element


[Link]([Link](0)); // Output: postman

(2) set() - Update an element at a specific index


[Link](0, "Playwright");

Page 165 of 214


Java Complete Study Notes | By Jatin Sir

// Replaces "postman" with "Playwright"


[Link](namesList);
// Output: [Playwright, null]

(3) contains() - Check if an element exists in the list


boolean data4 = [Link]("Playwright");
[Link](data4);
// Output: true

Add Elements from ArrayList to LinkedList !


addAll(Collection c) ➤ Appends all elements from the specified collection to the list
boolean result = [Link](al);
// nameList has [Playwright, null]
// adding [JMeter, cypress] from ArrayList al we have created at
the beginning.
[Link](namesList);
// Output: [Playwright, null, JMeter, cypress]

Common Methods
(1) size()
(2) clear()

➤ Returns the number of elements in the LinkedList


➤ Removes all elements from the LinkedList, making it empty

(1) size()
[Link]([Link]()); // Returns the number of elements in the LinkedList

(2) clear()
[Link](); // Removes all elements from the LinkedList
[Link](namesList); // Output: [] ➤ List is now empty

Return Types of LinkedList Methods


We Have Seen So Far
Methods That Return boolean

Method

Return
Type

Description

remove(Object o)

boolean

Removes the first occurrence of the

Page 166 of 214


Java Complete Study Notes | By Jatin Sir

specified element

contains(Object o)

boolean

Checks if the list contains the specified


element

addAll(Collection
c)

boolean

Adds all elements from another


collection to the list

Methods That Return an Element (Object)

Method

Return
Type

Description

get(int index)

Element

Retrieves the element at the given index

set(int index,
val)

Element

Updates and returns the previous value at


that index

remove()

Element

Removes and returns the first element


(head)

remove(int index)

Page 167 of 214


Java Complete Study Notes | By Jatin Sir

Element

Removes and returns the element at the


specified index

Methods That Return Other Types


Method

Return Type

Description

size()

int

Returns the number of elements in the list

clear()

void

Clears all elements (returns nothing)

Array Traversal Using For Loop !


for(int index = 0;index < [Link]();index++){
[Link]([Link](index));

Enhanced For Loop


for(String names : namesList){
[Link](names);
}

Loop Using Iterator


Wanna revise Iterator >>

Iterator<String> iteratorList = [Link]();


// [Link]() calls the iterator() method from the Iterable interface
// and returns an Iterator object for the namesList.
// 'iteratorList' is a reference variable pointing to that Iterator object.
while ([Link]()) {
// Checks if there is a next element in the list
String currentName = [Link]();
// Retrieves the next element and stores it in 'currentName'
[Link](currentName);
}

Page 168 of 214


Java Complete Study Notes | By Jatin Sir

For Each using lambda & Method


Reference

//For each using lambda


[Link](x-> [Link](x)); // Lambda expression — for each element x,
print
it
[Link]([Link]::println); // :: > Method reference — shorthand for the above
lambda expression

What is Deque?
Deque stands for Double Ended Queue.
Double Ended Queue means - we can insert and remove elements from both ends —
front and back.
Deque allows BI-DIRECTIONAL traversal — from front to back and back to front !

// Creating a LinkedList and using add() to add elements


LinkedList<String> namesList = new LinkedList<String>();
[Link]("java");
[Link]("python");
[Link]("selenium");
[Link]("java");
[Link]("postman");
[Link](0,"cypress");

// Inserts "cypress" at index 0, shifting others to the

right
[Link](null);
null]

// o/p - [ cypress, java, python, selenium, java, postman,

Methods in Deque
addFirst(e)
➤ Adds the element at the front of the list
addLast(e)
➤ Adds the element at the end of the list
get(index)
➤ Retrieves the element at the specified index (from List)
getFirst()
➤ Retrieves the first element in the list
getLast()
➤ Retrieves the last element in the list
offerFirst(e) ➤ Adds element at the front and returns true if successful
offerLast(e)
➤ Adds element at the end and returns true if successful
pollFirst()

Page 169 of 214


Java Complete Study Notes | By Jatin Sir

➤ Removes and returns the first element, or null if list is empty


pollLast()
➤ Removes and returns the last element, or null if list is empty
peekFirst()
➤ Returns the first element without removing it
peekLast()
➤ Returns the last element without removing it
push(e)
➤ Adds element at the front (stack-style)
pop()
➤ Removes and returns the first element (stack-style)

Deque Method Examples


[Link]("docker") // return void
[Link]("Rest Assured"); // return void
[Link]([Link](0));
// from List Interface
[Link]([Link]()); //From Deque
[Link]([Link]([Link]() - 1)); // From List Interface
[Link]([Link]()); //From Deque
[Link]([Link]("python"));// returns boolean
[Link]([Link]("java"));
String pollFirstResult = [Link]();
String pollLastResult =[Link]();
String peekFirstResult =[Link]();
String peekLastResult = [Link]();
[Link]("javascript");
[Link]();// Removes and returns the first item → which is "javascript"

Return Types Of Deque Methods


boolean ➤ offerFirst(), offerLast()
E (element) ➤ get, getFirst, getLast, pop
void ➤ addFirst(), addLast(), push()
E or null ➤ poll() and peek() methods (they safely return null if list is empty)

Brain Teasers
Q1: What’s the difference between addFirst() and
offerFirst()?
Both add an element to the front (head), but for:
addFirst() - return type is void
offerFirst() returns type is boolean

Q2: What is the return type of pollFirst() and when would it


return null?
Return type: E (element type)
It returns null if the deque is empty (safe version of removeFirst())

Q3: If you use push("java") and then pop(), what happens?

Page 170 of 214


Java Complete Study Notes | By Jatin Sir

push() adds to the front


pop() removes from the front
So we’ll get "java" removed — it behaves like a stack

Q4: Can a LinkedList be used as a Queue, Stack, and


Deque?
Yes! LinkedList implements List, Deque, and Queue, so it can function as:
A Queue (FIFO) → using add(), poll()
A Stack (LIFO) → using push(), pop()
A Deque → using addFirst(), removeLast(), etc.

Q5: What happens if you call pop() on an empty LinkedList?


It throws a NoSuchElementException. Unlike poll(), which returns null.

Q6: How can you iterate backward in a Deque?


By using descendingIterator():
Iterator<String> revItr = [Link]();
while ([Link]()) {
[Link]([Link]());
}

Q7: Can you store null in a LinkedList used as a Deque?


Yes! LinkedList allows null elements.

Q8 :Difference Between Polling and Peeking in Deque ?

Vector
Hierarchy Diagram

Vector was introduced in Java 1.0 to overcome limitations of traditional arrays.


It is part of [Link] package.

It is a re-sizable array that can store elements dynamically.


Every method in Vector is synchronized, making it thread-safe.
However, this comes at the cost of slower performance.

Syntax:
Vector<Integer> vector = new Vector<Integer>();
Key Characteristics
Internally works like an array (with indexed elements).
Resizes automatically: When full, the capacity doubles (2x).
All methods are thread-safe → Safe for multi-threaded environments.

Page 171 of 214


Java Complete Study Notes | By Jatin Sir

Due to synchronization overhead, it is slow, even in single-threaded use cases.


Became legacy after Java 1.2, retained only for backward compatibility.
ArrayList was introduced as a DIRECT REPLACEMENT FOR VECTOR in Java 1.2, as
part of the Java Collections Framework.
Vector vs ArrayList
Feature
Vector
ArrayList
Introduced In
Java 1.0
Java 1.2 (as part of Collection
Framework)
Package
[Link]
[Link]
Thread
Safety
Synchronized
(Thread-safe)
Not synchronized (Not thread-safe)
Performance
Slower due to
synchronization
Faster in single-threaded environments
Capacity
Growth
Grows by 100%
(doubles capacity)
Grows by 50%
Default Use
Case
Multi-threaded
environments
Single-threaded environments
Flexibility in
Threads
Always
synchronized

Page 172 of 214


Java Complete Study Notes | By Jatin Sir

Can be made synchronized using


[Link]() or
CopyOnWriteArrayList
Status
Legacy class (use
discouraged)
Preferred in Java collections
Methods In Vector!
import [Link].*;
public class Vector101 {
public static void main(String[] args) {

// Creating a Vector of Integers

Vector<Integer> vector = new Vector<>();

// Adding elements using legacy method addElement()

[Link](10); // Legacy method


[Link](20);
[Link](40);
[Link](50);
[Link](650);
[Link](vector); // Prints all elements

// Accessing elements - Legacy methods

[Link]([Link]());

// First element (Legacy)

[Link]([Link]());

// Last element (Legacy)

[Link]([Link](2));

// Element at index 2 (Legacy)

[Link]([Link](2));

Page 173 of 214


Java Complete Study Notes | By Jatin Sir

// Collection interface method

// ------------------------------// Removing elements from Vector

// ------------------------------[Link](3);

// Remove by index (Collection)

[Link](0);

// Legacy method

[Link](new Integer(20));

// Remove by value (Collection)

[Link](new Integer(650)); // Legacy remove

// -------------------------------// Iteration using Iterator

// Iteration using Iterator (Way to retrieve elements from any Collection)

// -------------------------------[Link]("---- Iterator ----");

Iterator<Integer> vIterator = [Link]();


while ([Link]()) {
[Link]([Link]()); // / Retrieves each element from the Vector
}

// -------------------------------// Iteration using Enumeration (Legacy) -

// Enumeration is a legacy interface used to traverse (iterate) through the elements of

legacy collections like Vector and Hashtable.

Page 174 of 214


Java Complete Study Notes | By Jatin Sir

// -------------------------------[Link]("---- Enumeration ----");

Enumeration<Integer> vEnum = [Link]();


while ([Link]()) {
[Link]([Link]()); // Iterates using Enumeration
}
//size() gives the total number of elements present in vector
[Link]([Link]());

// Total elements

// Ensures capacity is 35 (increases if needed)

[Link](35); // when we know the capacity of vector

// Convert vector to Array

Integer[] data = [Link](new Integer[0]);

// Collection

Integer[] myData = new Integer[[Link]()];


[Link](myData);

// Legacy copy method

[Link]([Link](myData));
}
}
Stack

// Prints copied array

+-------------------------+
+-------------------------+

extends
+--------------------------+

Page 175 of 214


Java Complete Study Notes | By Jatin Sir

+--------------------------+

implements
+-------------------------+
Synchronized | Vector (class)
| Legacy Class (retained only for backward compatibility)
Thread safe +-------------------------+ since java 1

extends
+------------------------+
Synchronized | Stack (class)
| LIFO ,
Thread safe +------------------------+
child of vector
Properties of Stack
Stack is a Linear Data structure from [Link].
It is a re-sizable array.
Follows LIFO - Last in Frst Out principle.
Stack is a child of vector. Since vector is synchronized - Stack is also synchronised( thread
safe).
JVM uses stack data structure for method excecution.
Stack Working - LIFO: Last-In First-Out
Imagine we have 5 books stacked on a table — one over the other.
We place Book 1 on the table.
Then you place Book 2 on top of Book 1.
Then Book 3 on top of Book 2...
Then Book 4, then finally Book 5 on top.
Top of Stack
┌──────────┐ ◄── Book 5 (last inserted)
├──────────┤
├──────────┤
In Stack, the top pointer always points to the last added element.
├──────────┤
├──────────┤
| Book 1 | ◄── Book 1 (first inserted)
└──────────┘
Bottom of Stack
Now if we want to take a book - The only way is to take the top book first.

Page 176 of 214


Java Complete Study Notes | By Jatin Sir

That means - We take Book 5, then Book 4, then Book 3, and so on...
We CANNOT access Book 1 directly unless we remove all the books above it.
This is how a Stack works in Java - The last item added (Book 5) is the first one to be removed
>> This is called LIFO (Last-In First-Out).
Stack Operations
push() > Add elements to stack.
pop() > Removes and returns the top element.
peek() > Returns the top element without removing it.
empty() > cReturns true if the stack has no elements, otherwise returns false.
search() - Search whether element present in stack or not. > If present,
[Link](element) returns the 1-based position from the top of the stack. > If not
present, it returns -1.
Initial Stack:
After POP:
After PEEK:
┌──────────┐
┌──────────┐
┌──────────┐
| Book 3 | ← Top
| Book 2 | ← Top
| Book 2 | ← Peeked (still in stack)
├──────────┤ [Link]() ├──────────┤ Popped
├──────────┤

Book 2 -------------> Book 1 ----------> Book 1

├──────────┤ Removes &


└──────────┘ [Link] └──────────┘
| Book 1 | returns Book 3 Top = Book 2
Returns Book 2 (not removed)
└──────────┘
Bottom of stack → Book 1 (First inserted)
SET - Set is the only
interface in the
Collection framework
that is idempotent by
design !
Non Linear Data Structure which store only unique values.

Page 177 of 214


Java Complete Study Notes | By Jatin Sir

Only unique values are stored - No duplicates allowed.


Idempotent** in nature → Adding the same element multiple times has no effect after the first
addition.
Idempotent means - How many times the operation is performed, results remain the same.
Can have only one NULL value.
Order of the elements may or may not be maintained depending upon the
implementation(whether we use Hashset or LinkedHashset).
Hashset - Do not maintain order.
LinkedHashset - Maintain order.
List does not hav any implementation for retrieving elements in sorted order.
Can retrieve elements in sorted order if Treeset is used.
No get() Method in Set. In Set, elements are not stored by index, so we cannot use get(index)
like we do with a List.
Set use Iterator or for-each loop to traverse the elements one by one.
Hashset
Hashset is a class which implements Set Interface.
Hashset internally uses hashmap, so insertion order is not preserved. Elements appear in
random order when iterated.
Single null value is allowed in hashset.
HashSet extends AbstractSet.
AbstractSet implements Set.
How to declare a Hashset?
HashSet<String> hashset = new HashSet<String>();
HashSet Methods
[Link]("India");
[Link]("Scotland");
[Link]("Netherlands");
[Link]("Kashmir");// Kasmir will be added once as set is idempotent
[Link]("Kashmir");
[Link]("Kashmir");
How to maintain order in a set?
By using Linked Hashset.
LinkedHashSet<String> Linkedhashset = new LinkedHashSet<>();
[Link]("India");
[Link]("Scotland");
[Link]("Netherlands");
[Link]("Kashmir");// Kashmir will be added once as set is idempotent
[Link]("Kashmir");

Page 178 of 214


Java Complete Study Notes | By Jatin Sir

[Link]("Kashmir");
[Link]("LinkedHashset is" + Linkedhashset);
Treeset
TreeSet<String> treeSet = new TreeSet<>();
[Link]("India");
[Link]("Scotland");
[Link]("Netherlands");
[Link]("Kashmir");// Kasmir will be added once as set is idempotent
[Link]("Kashmir");
[Link]("Kashmir");
[Link]("Treeset is" + treeSet);
How to retrieve elements from Set?
The Set interface does not provide a get() method — because Sets are **not index-based.
To access elements, we use Iterator (from the Iterator interface) or **enhanced for-each loops.
For each for Iteration
for (String data : treeSet){
[Link](data);
}
Iterator for traversing through set
Iterator<String> dataIterator = [Link]();
while([Link]()){
[Link](dataIterator);
}
Iterator ➤ Declares a variable dataIterator of type Iterator (used to loop through String
elements).
[Link]() ➤ Calls the iterator() method on treeSet. ➤ This method returns an
Iterator object that knows how to go through the TreeSet.
Assignment (=) ➤ The returned Iterator object is stored in the dataIterator variable.
while ([Link]()) ➤ Checks if there is a next element available in the set.
➤ Returns true if there is one, otherwise false.
[Link]() ➤ Retrieves the next element in the set. ➤ Moves the pointer
forward to the next item.
[Link](...) ➤ Prints the current element.
Iterator We are declaring a variable dataIterator of type Iterator Interface — used to loop
through String values. [Link]() This calls the iterator() method on treeSet,
which returns an Iterator object.
Iterator is an interface from [Link].
iterator() is a method inside the Iterable interface.

Page 179 of 214


Java Complete Study Notes | By Jatin Sir

All collections like List, Set, etc., implement Iterable, so we can use .iterator() on them.
🔸 LinkedHashSet → ✅ Maintains insertion order
🔸 HashSet → ❌ No guaranteed order
🔸 TreeSet → ✅ Sorted order (not insertion order)
Methods in set

// isEmpty() - check whether a set is empty or not

HashSet<String> set = new HashSet<>();


[Link]();
[Link]([Link]());
//size() - total num of elements in set
[Link]([Link]());

// contains() - check whether a particular obj is present or not in the set - returns
boolean

[Link]([Link]("India"));
[Link]([Link]("Delhi"));

// remove() - remove an obj from set

[Link]([Link]("Kashmir"));
[Link](hashset);
}
How to access elements in set through
index?
Not possible as set doesn't have any index
Is there a way where
we can access set
elemenst through
index?
Yes, convert it into set and then we can access elements using get().
HashSet<String> hashset = new HashSet<String>();
[Link]("India");
[Link]("Scotland");
[Link]("Netherlands");
[Link]("Kashmir");// Kasmir will be added once as set is idempotent
[Link]("Kashmir");

Page 180 of 214


Java Complete Study Notes | By Jatin Sir

[Link]("Kashmir");
ArrayList<String> al = new ArrayList<>(hashset);
[Link](al);
[Link]([Link](0));

Internal Working Of
Hashset
We are focusing on understanding the
following 2 points :
(1) How set maintains uniqueness ?**
(2) why hashset does not maintain order?**
To understand how Set maintains uniqueness, it's helpful to learn how Map works
internally. So, Good to have a read about Map first.

How set maintains uniqueness ?

> Set maintains uniqueness by using a HashMap internally.


> When we create a HashSet object, Java secretly uses a HashMap in the background to store
the elements.
> Since HashSet internally uses a HashMap, it relies on the Map’s unique key property to
ensure that the elements in the Set remain unique.

Why Does HashSet Use HashMap


Internally?
Because HashMap already has the logic to:
> avoid duplicates
> store items using hashing and buckets
> retrieve items quickly

> So instead of writing all that logic again, HashSet reuses HashMap internally.
## What happens when we create a Hashset ?
**When we create a HashSet, Java internally creates a HashMap to store its elements**.

Set<Integer> set = new HashSet<>(); // Creating a Hashset


Map<Integer, Object> map = new HashMap<>(); // java internally creates a HashMap
HashSet() Constructor
public HashSet() {
map = new HashMap<>(); // Hashset Constructor
}
> When we create HashSet, the default constructor of the HashSet class is called.
> Internally, the HashSet() constructor creates a HashMap to store its elements.
> This map stores the set elements as keys, which ensures uniqueness - because Map does
not allow duplicate keys.

Page 181 of 214


Java Complete Study Notes | By Jatin Sir

> Internally, HashSet instantiates a HashMap to manage its elements.


What is a Map? How map store
elements?
Map is an interface that represents an associative array — a data structure that stores data in
key–value pairs.
We can access a VALUE in a Map by using its KEY — this process is called a lookup.
+------------------+
+------------------+
What happens when we add elements
to a hashset?
Set<Integer> set = new HashSet<>();
[Link] (1). // Adding 1 to Hashset
Internal Flow Overview
[Link](1) // Adding an element to set

[Link](1, PRESENT) // Hashset internally calls put() method of a HashMap which put
elements inside the map.

putVal(hash(1), 1, PRESENT, false, true) // hash(key) calculates a hashcode for the element.

// Hashcode >> is the numeric representation of an object and

hashcode of a number is number itself.

// The element (1) added to the HashSet becomes the KEY in the

internal HashMap

// PRESENT is a dummy object used as the VALUE, It is a constant

(static FINAL object)


+----------------+
+-------------------+
+-----------------------+

[Link](1) ----► [Link](K, V) ----► [Link](1,


PRESENT)

+----------------+

Page 182 of 214


Java Complete Study Notes | By Jatin Sir

+-------------------+
+-----------------------+

PRESENT is a constant(static final Object)
Wanna see - How [Link]() works
internally?
public boolean add(E e) { // e becomes the key (element added in set)
return [Link](e, PRESENT) == null; // add () method of hashset internally calls put()
method of map.

// PRESENT is the constant dummy value ((static final Object))

// == null >> Checks if [Link]() return null — meaning it’s a new entry

(i.e., not a duplicate)


}

// Logic:

> If the key is NEW:


• [Link]() returns NULL
• add() returns TRUE
• element was added
If the key ALREADY EXISTS:
• [Link]() returns the OLD value (which is always PRESENT in HashSet)
• add() returns FALSE
• element was a duplicate
What is PRESENT?
private static final Object PRESENT = new Object(); // PRESENT (all caps) → by Java
convention, constants are named in uppercase
PRESENT is a constant placeholder object used as the value in the internal HashMap.
It’s a dummy object to complete the key–value pair — we only care about the keys,
which are the actual set elements.
What Happens After [Link]()? —
How putVal() works?
public V put(K key, V value) {. // put() is a public method in HashMap
return putVal(hash(key), key, value, false, true); // putVal() is an internal method inside the
HashMap class — not in Set or HashSet.

Page 183 of 214


Java Complete Study Notes | By Jatin Sir

}
The put() method of HashMap doesn’t directly insert elements.
Since HashSet uses a HashMap internally, calling [Link](e) ends up calling [Link](e,
PRESENT), which in turn calls putVal().
putVal( ) performs the actual insertion into the appropriate bucket.
What putVal() Does?
(1) Calculates the hash
HashCode is a numeric representation of an object.
For numbers, the hashcode is the number itself
(2) Finds the right bucket
Using the formulae - hashCode % capacity
(3) Handles collisions
If another key already exists at the same bucket
(4) Checks for duplicates
Compares using equals() to see if the key already exists
(5) Inserts or updates
Adds a new entry or replaces the existing one if the key matches
Do Elements in a HashSet Maintain
Order?
> No — the elements in a HashSet do not maintain insertion order.
> That’s because:
(1) A HashSet does not support index-based storage like a List or Array.
(2) It stores elements based on their hashcode, not the order in which they were added.
(3) Internally, it uses a HashMap, which organizes elements into buckets based on
hashing rather than positions.
So when we iterate over a HashSet, the order may appear random or shuffled, and it
can vary depending on the hash distribution.

Set<Integer> dataSet = new HashSet<Integer>();


// Element retrieval order will not be maintained

[Link](0);
[Link](1);
[Link](16);
[Link](2);
[Link](32);
[Link](17);

[Link](dataSet); O/P - order not maintained - [0, 16, 32, 1, 17, 2]

HashSet Class

Page 184 of 214


Java Complete Study Notes | By Jatin Sir

public class HashSet<E>

extends AbstractSet<E>

implements Set<E>, Cloneable, [Link]

> The parent class of HashSet is AbstractSet.

> HashSet also implements 3 interfaces:

- Set – to follow the set contract (no duplicates, unordered)

- Cloneable – so that it can be cloned (copied)

- Serializable – so that it can be serialized (saved/transferred)

NOTE:

extends → means HashSet inherits functionality from the AbstractSet class

implements → means HashSet promises to provide implementations for the methods


defined in those interfaces

Why is map marked as transient in


HashSet?

private transient HashMap<E,Object> map; // The map is the field being marked as
transient.

What does transient mean?

In Java, the transient keyword tells the JVM:

Do not serialize the map when converting the object to a byte stream (e.g., during file
save or network transfer).

NOTE:

Serialization is the process of converting an object into a byte stream, so it can be: (1)
Saved to a file (2) Transferred over a network

Why skip serialization of the internal


map?
Because, HashSet is backed by a HashMap internally.

Page 185 of 214


Java Complete Study Notes | By Jatin Sir

We don’t want to serialize the entire internal structure — like buckets, hashcodes, load
factors, etc.

Instead, Java uses custom serialization logic to write only the actual set elements, not
the full map.

Benefits of Marking map as transient


Encapsulation: Keeps internal map structure hidden from external systems during
serialization.

Smaller File Size: Avoids writing unnecessary internal data to file or stream.

Backward Compatibility: Makes it easier to read data even if internal implementation


changes in future versions.

How Hashmap of string Type works ?

static final int hash(Object key) { // Step 1: Get the key's hashCode()

int h; // Declares a temporary variable to hold the hashCode

// If key is null → hash is 0 → goes to bucket 0

return (key == null) ? 0 : (h = [Link]()) ^ (h >>> 16);

// Otherwise →
// 1. Calculate hashCode and store in 'h'
// 2. Right shift h by 16 bits
// 3. XOR the original and shifted values for better distribution
}

[Link]() → gives the original hash (can be a large int).

h >>> 16 → shifts bits 16 places right, dropping lower precision.

^ (XOR) → combines both to reduce collisions and spread keys evenly.

If key is null, it avoids error and returns 0.

Can We Add null to a HashSet? Where


is it stored?

Yes, null can be added to a HashSet.

Behind the scenes, HashSet uses a HashMap — and HashMap allows ONE NULL KEY.

When we add null, the key is treated specially, It directly goes to bucket 0 - INDEX 0 of

Page 186 of 214


Java Complete Study Notes | By Jatin Sir

the internal table.

No hashCode is calculated for null — because it would throw a NullPointerException.

Java internally handles this with:

return (key == null) ? 0 : (h = [Link]()) ^ (h >>> 16);

So null → returns 0 → goes to index 0.

Only one null is allowed in a Set, because Set doesn’t allow duplicates.

How Does [Link]() Work?

[Link](1); // Internally, this calls: [Link](1);

Because a HashSet uses a HashMap to store its elements, the contains() method in
HashSet checks whether the element exists as a key in the internal map.

Why Is contains() So Fast?


The method [Link]() uses hashing. So, Average time complexity = O(1)
(constant time)

This means: Lookup is extremely fast, even with large data sets.

The speed is one of the main reasons HashSet is preferred when checking for
existence.

Hashing Mechanism - How HashSet


Handles Duplicates ?
Default capacity of a hashset : By default, when we create a HashSet without specifying
the capacity, it internally creates a HashMap with 16 buckets — indexed from 0 to 15.

Index (Bucket)

+------+

NODE - The actual object stored inside a bucket

+----------+----------+----------+----------+

| 0 | ----> | hashCode | key


+------+

| value | next

| <-- Elements in a NODE.

Page 187 of 214


Java Complete Study Notes | By Jatin Sir

+----------+----------+----------+----------+

| 1 |
+------+
| 2 |
Hashcode >> is the numeric representation of an object and hashcode of a
number is number itself.
+------+
| 3 |

Key → The element added to the HashSet

+------+
| 4 |
value → A dummy constant object called PRESENT (used to complete the
key–value pair)
+------+.
| 5 |
collision

next → A pointer (reference) to the next node in the bucket in case of a

+------+
| 6 |
+------+
| 7 |
+------+
| 8 | ← Bucket 8
+------+
| 9 |
+------+
| 10 | Each index in the array is called a BUCKET.
+------+
| 11 |
+------+
| 12 | ← Bucket 12
+------+
| 13 |
+------+
| 14 |
+------+
| 15 |. ← Bucket 15
+------+

What’s Inside Each Bucket?

Page 188 of 214


Java Complete Study Notes | By Jatin Sir

Each bucket can hold one or more nodes, depending on how many elements map to
the same index.
Each Node contains the following:

class Node<K, V> {

final int hashCode; // hashCode → Numeric representation of the key (used to find
the bucket index)

final K key;

// key → The element added to the HashSet

V value;
// value → A dummy constant object called PRESENT (used to
complete the key–value pair)

Node<K, V> next;


during collisions)

// next → A pointer to the next node in the same bucket (used

What happens when we add


elements?

[Link](0);

[Link](1);
[Link](2);

When these elements are added to the HashSet, they are stored internally as shown
below (assuming default capacity = 16):

+------+

+-----------------------+ // hashCode = 0

| 0 | ───────► | [0][0][C][null]
+------+

| // key = 0

+-----------------------+ // value = C (constant)


// next = null (no collision)

+------+

Page 189 of 214


Java Complete Study Notes | By Jatin Sir

+-----------------------+

| 1 | ───────► | [1][1][C][null]
+------+

+-----------------------+

+------+

+-----------------------+

| 2 | ───────► | [2][2][C][null]
+------+

← hashCode 1, key 1

← hashCode 2, key 2

+-----------------------+

How is the Bucket Index Calculated?

When we add an element to a HashSet, Java internally calculates the bucket index
using:

bucketIndex = hashCode(key) % capacity; // remainder determines the bucket index

This remainder determines the bucket index where the element will be stored.

Since the default capacity is 16, the available bucket indexes range from 0 to 15.

How to calculate hashcode for 16?


bucketIndex = hashCode(key) % capacity.

hashCode(16) % 16 = 0 // Remainder is 0, we already have an element at bucket 0 (


collision)

A hash collision occurs when two different keys produce the same hash index, meaning
they are assigned to the same bucket in the hash table.

Elements 0 and 16 are stored in the same bucket, called COLLISION.

How HashSet Handles Collisions?

Page 190 of 214


Java Complete Study Notes | By Jatin Sir

When two elements map to the same bucket, Java stores them as nodes in a linked list
inside that bucket.

Here’s how it looks internally:

+------+

+----------+----------+----------+----------+

| 0 | ──────────────► | hashCode | key


constant (PRESENT)
+------+

| value | next

|.

C = dummy

+----------+----------+----------+----------+
| 0

| 888

next = pointer to the next node in

the bucket
+----------+----------+----------+----------+

+----------+----------+----------+----------+ Each bucket can store one or
more entries (as nodes), especially
| 0

| 16

Page 191 of 214


Java Complete Study Notes | By Jatin Sir

| null

| in case of collisions.

+----------+----------+----------+----------+

(888 = memory address of next node)

What if number of entries in a single


bucket exceeds a threshold (usually
8)?

> If the number of entries in a single bucket exceeds a threshold, the linked list is
automatically converted into a balanced tree .

> Java 8 Enhancement - Tree Conversion.(specifically, a Red-Black Tree) to improve


performance.

> This transformation helps in:

Faster lookup (O(log n) instead of O(n))

Maintaining performance in collision-heavy scenarios.

How HashSet Uses hashCode() and


equals() to Ensure Uniqueness?

A HashSet in Java uses HASHING to determine where to store elements and equality
checks to avoid duplicates.

This is done using two important methods: (1) hashcode() (2) equals()

(1) hashCode() - Converts an object into an integer hash

This hash is used to determine the bucket/index where the element should go in
memory

(2) equals() - equals() checks if two objects are logically equal, even if they land in
the
same bucket due to matching or colliding hashCode() values.

hashCode() is just a number used for bucket placement — and it’s possible for two
different objects to return the same hashcode. This is called a hash collision.

That’s why Java calls equals() to confirm whether the objects are truly duplicates before
rejecting the second one.

Page 192 of 214


Java Complete Study Notes | By Jatin Sir

For proper functioning - hashCode() and equals() must work together to ensure
uniqueness in a HashSet. - That’s how HashSet avoids storing duplicate elements.

Load Factor and Resizing


The load factor defines how full the HashSet can get before it resizes.

Default load factor: 0.75

This means: when the number of elements exceeds 75% of the capacity, the HashSet
will resize (usually by doubling the capacity).

What Happens During Resizing?


When resizing is triggered:

All existing elements are rehashed (i.e., their bucket positions are recalculated).

They are placed into new buckets based on the new capacity.

This helps maintain constant-time performance for operations like add(), contains(), and
remove().

This process is automatic and internal — developers don't need to manually resize the
set.

Example:

If initial capacity = 16

Then 16 × 0.75 = 12

The 13th element will trigger resizing.

Comparison: HashSet vs
LinkedHashSet vs TreeSet

| Feature
TreeSet

| HashSet

| LinkedHashSet

|----------------------|----------------------------------|-------------------------------
-----------------|-------------------Order Maintained?
Yes (sorted order)

Page 193 of 214


Java Complete Study Notes | By Jatin Sir

| No

Internal Structure
| Red-Black Tree

| HashMap

Time Complexity
O(log n)

| O(1) average

| Yes (insertion order)

| HashMap + Doubly Linked List

| O(1) average

|Null Allowed?
| Yes (only one null allowed)
No (throws `NullPointerException`)

| Yes

Use Case
| Fast lookups with no ordering
access
| Maintain sorted order

| Maintain insertion order + fast

Summary

🔹HashSet and HashMap are classes in Java that implement the Set and Map
interfaces respectively.

🔹 HashSet uses a HashMap internally to store elements and ensure uniqueness.


🔹 All elements added to a HashSet become the KEYS of the internal HashMap.
🔹 A constant dummy object called PRESENT is used as the value in the map.
🔹 [Link](e) internally calls [Link](e, PRESENT).
🔹 If [Link]() returns null → element is new → added successfully.

Page 194 of 214


Java Complete Study Notes | By Jatin Sir

If [Link]() returns PRESENT → duplicate → not added.

🔹 The internal map is marked transient to avoid being serialized with all internal
structure.

🔹 Serialization only includes actual elements — not buckets, hashcodes, etc.


🔹 Each bucket (0 to 15 by default) holds nodes (key, value, next) for entries.
🔹 Collisions are handled using a linked list inside buckets.
If bucket entries exceed a threshold (usually 8), they are converted into a balanced
tree (Java 8+).

🔹 HashSet relies on two methods to avoid duplicates:


- `hashCode()` to determine bucket placement.
- `equals()` to check actual object equality inside same bucket.

🔹 Only one null value is allowed in HashSet (stored at index 0).


🔹 HashSet does not maintain insertion order because elements are stored based on
hash, not position.

🔹 Load Factor : HashSet uses a HashMap internally, so it inherits its resizing


mechanism.

Default Load Factor = 0.75


This means: when 75% of the internal capacity is filled, resizing is triggered.

🔹 Time Complexity for operations like add(), remove(), contains() = **O(1)** (on
average)

🔹 Compared to:
- LinkedHashSet → maintains insertion order
- TreeSet → maintains sorted order, slower operations (O(log n))

🔹 Use a HashSet when : We need fast search, insertion, and deletion (average time
complexity: O(1))

- We want to store unique items


- Don’t care about order
- Need fast access and lookups

Map
> Map is part of the Java Collections Framework, but it DOES NOT EXTEND the
COLLECTION INTERFACE.

> This is because Map stores KEY - VALUE Pairs, unlike other collections like `List` or
`Set`, which store individual elements.

Page 195 of 214


Java Complete Study Notes | By Jatin Sir

Map Hierarchy

NOTE :
Hashmap (class) implements Map (interface)

LinkedHashMap (class) implements Map (interface)

TreeMap (class) implements Map (interface)

Class Implements Interface means >>

(1) The class gets access to all the method signatures in the interface.

(2) The class must write the actual logic (method bodies) for them.

What is a Map ?
> Map is an interface that represents an associative array. Association is between KEY
& VALUE.

+------------------+
| Map (Key, Value) |
+------------------+

Page 196 of 214


Java Complete Study Notes | By Jatin Sir

Chapter 13: Advanced Java Topics


Threads, Streams, Lambda, Design Patterns, Interfaces

> Whenever we want to retrieve the value, we use the KEY that is associated with that
VALUE. This is called LOOK UP OPERATION (Retrieval).
> LOOK UP happens at super speed.
> Perfomance of get() or the LOOK UP opearation is O(1) > Time Complexity.
> Example use: Counting frequencies, lookups (dictionary).
What is Timecomplexity O(1) means?
> No matter how many key-value pairs are stored in the map, whether it's 10, 100,
1000, or even 1 million.
> Retrieving a value using a KEY will take the same amount of time > So
TimeComplexity is Constant - O(1)
What is Hashing ? How Hashing
Works in HashMap ?
Hashing is the process of converting a LARGE OBJECT into a FIXED LENGTH
INTEGER VALUE — called hashCode.
This integer value is the bucket index where the NODE will be stored ( KEY & VALUE)
Reduces collisions and enables fast retrieval.
bucketIndex = hashCode % capacity;
Example: Hashcode of an Integer Object
Integer i = 10;

// or Integer i = new Integer(10); // // Both lines create Integer objects in different


ways

[Link]([Link]()); // Output: 10 // Hashcode of any integer obj is number


itself.
+-------------------------+

// Integer is a wrapper class.

+-----------+-------------+

// Parent of integer is Object.

// Object class provides a method called

Page 197 of 214


Java Complete Study Notes | By Jatin Sir

hashCode(), which generates hashcode using hashing to convert


+------+------+
| Object
| ← Parent of Integer
large objs into fixed len integer
+------+------+
+------+------+
| hashCode() | ← Method in Object class
+-------------+
| Generates hashcode using hashing which converts larger object into fixed
length integer value
v
For Integer: hashCode() = value itself // Example: new Integer(10).hashCode() = 10
How is hashCode() calculated for a
String?
Java uses a specific formula to calculate the hashcode of a String:
hashCode = s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
s[i] is the ith character of the string
^ means exponentiation (power)
31 (base multiplier) is a prime number used to reduce collisions.
+------------------------------+
String s = "abc"
| ----> String is converted to character array [a,b,c]
+------------------------------+
hashCode formula:
|s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]*31^0 | 31 is base multipier ( primenumber )
-> Less collisons
= 'a'*31^2 + 'b'*31^1 + 'c'*31^0
= 97*961 + 98*31 + 99*1
= 96354 > fixed length integer
So here LARGE STRING is converted to FIXED LENGTH INTEGER.
What is the CONTRACT BETWEEN
hashCode() and equals()?
When we create a custom class (like Student or Employee) and plan to store its objects
in collections like HashMap, HashSet, or Hashtable,
we MUST OVERRIDE BOTH equals() and hashCode() — this is known as the contract
between them.
These methods should be based on our class's instance variables, so that logically

Page 198 of 214


Java Complete Study Notes | By Jatin Sir

equal objects behave correctly in hash-based collections.


Two objects are considered equal when:
(1) Their hashCode() is the same.
(2) Their instance variable values match.
Java's Contract Rule !
==================================================================
========================================
If two objects are equal according to .equals() → they must return the same hashCode()
But if two objects have the same hashCode() → they may or may not be equal
(because of hash collisions)
==================================================================
========================================
Code showing Java's Contract Rule !
public class Test {
public static void main(String[] args) {
String s1 = "Java";
String s2 = "Java";
[Link]([Link](s2));

// true → content is same

[Link]([Link]());

// e.g., 2008614266

[Link]([Link]());

// 2008614266

}
}
Why this proves the CONTRACT ?
Both s1 and s2 have the same content
So .equals() returns true
And their hashCode() is also the same
This proves:If two objects are equal using .equals() -> they must have the same
hashCode().
Why Should We Override Both in
Custom Classes?

Page 199 of 214


Java Complete Study Notes | By Jatin Sir

Whenever we create a custom class (like Student, Employee, etc.) and plan to use it in
hash-based collections like HashMap or HashSet,
we must override both equals() and hashCode().
.equals() → defines logical equality (based on instance variables)
.hashCode() → ensures equal objects go to the same bucket
> Overriding equals() and hashCode() ensures:
>>Objects with same values are treated as equal
>>Hash-based collections work as expected
What Happens If We Don’t Override?

// Even if two objects have same data:

Student s1 = new Student(1, "Athira");


Student s2 = new Student(1, "Athira");

// Without overriding equals() and hashCode()

[Link]([Link](s2)); // false
[Link]([Link]() == [Link]()); // maybe false
HashMap will treat s1 and s2 as different keys,even though they "look" the same!
Overriding both makes sure our object behaves correctly in collections.
[Link]() vs [Link]() –
What’s The Difference?
When overriding the hashCode() method in our custom class, we typically choose
between two approaches:
1. Use the default hashCode() method inherited from the Object class.
2. Use the utility method [Link]() introduced in Java 7
What is [Link]() - The
Default Method !
[Link]() – from [Link]
Object is the parent of all classes in Java.
Default method inherited by every class in Java.
Returns a hash based on the memory address (if not overridden).
Can lead to more collisions unless overridden properly.
Not null-safe.
Usually not used directly in custom hash logic.
Object obj = new Object();
[Link]([Link]()); // Prints the default hashCode based on memory
address

Page 200 of 214


Java Complete Study Notes | By Jatin Sir

What is [Link]() – The Utility


Method for Custom Classes !
[Link]() – from [Link]
A utility method (static) introduced in Java 7
Used to generate a hash code by combining multiple fields
Internally calls [Link]() → which is null-safe
Great for use in custom class implementations of hashCode()
public int hashCode() {
return [Link](id, name); // Combines both fields
}
[Link] ( ) OR [Link]( ) Which one to prefer?
When overriding the hashCode() method in our custom class, we have two options:
(1) Use the default hashCode() from the Object class.
OR
(2) Use the utility method [Link]() introduced in Java 7.
But which one should we use?
Always Prefer: [Link]() >> LESS COLLISIONS
Because it:
> Combines multiple fields into one hash
> is null-safe
> Reduces hash collisions
> Makes our code cleaner and readable
[Link]() (Default)
> Comes from [Link]
> Based on memory address (if not overridden)
> Not null-safe
> Not useful for checking equality of two objects with same data
> Always choose the one with less collision
How to Properly Override hashCode()
and equals() in a Custom Class !
import [Link];
class Employee { // Custom class to show equals() and hashCode()
int id;
String name;
Employee(int id, String name) {
[Link] = id;
[Link] = name;
}

Page 201 of 214


Java Complete Study Notes | By Jatin Sir

// Preferred way to override hashCode()

// Uses [Link]() to combine multiple fields and reduce collision

@Override
public int hashCode() {
return [Link](id, name);
}

// Override equals() to define logical equality

// Two Employee objects are equal if their id and name are the same

// To generate the following - Right-click inside the class > Select Generate → equals()

and hashCode()
@Override
public boolean equals(Object o) {
if (this == o) return true; // If both references point to same object
if (!(o instanceof Employee)) return false; // If not same class, return false
Employee e = (Employee) o;
return [Link] == [Link] && [Link]([Link]);
}
}
-------------------------------------------------------------------------------------------------------------------
public class EmployeeRunner {
public static void main(String[] args) {

// Same data → equals() returns true

Employee e1 = new Employee(1, "Athira");


Employee e2 = new Employee(1, "Athira");

// hashCode() based on data, so both are equal

[Link]([Link]());

Page 202 of 214


Java Complete Study Notes | By Jatin Sir

// Same as e2

[Link]([Link]());

// Same as e1

[Link]([Link](e2));

// true

}
}
Internal Working Of Map !
> Map consists of an array/table which has a size of 16, with index from 0 to 15.
> Each index is called BUCKET.
> When we create a hashmap - HashMap <Integer,String> hmap = new HashMap(),
the follwing table will be created internally!
HashMap Memory Layout !
Index (Bucket)
+------+
NODE - The actual object stored inside a bucket
+----------+----------+----------+----------+
| 0 | ----> | hashCode | key
+------+
| value | next
| <-- Elements in a NODE.
+----------+----------+----------+----------+
+------+
Hashcode >> is the numeric representation of an object and hashcode of a
number is number itself.
+------+
Key → The element added to the HashSet
+------+
value → A dummy constant object called PRESENT (used to complete the
key–value pair)
+------+.
collision
+------+

Page 203 of 214


Java Complete Study Notes | By Jatin Sir

next → A pointer (reference) to the next node in the bucket in case of a


+------+
+------+
| 8 | ← Bucket 8
+------+
+------+
| 10 | Each index in the array is called a BUCKET > BUCKET holds a NODE
+------+
+------+
| 12 | ← Bucket 12
+------+
+------+
+------+
| 15 |. ← Bucket 15
+------+
What’s Inside Each Bucket?
**Each bucket can hold one or more NODES, depending on how many elements map to
the same index.**
Each node is going to be LinkedList.
---------------------------| Map = Array + LinkedList |

----------------------------
NODE !
NODE is the the actual object stored inside a bucket.
Each NODE contains the following:
class Node <K, V> {
final int hashCode; // hashCode → Numeric representation of the key (used to find
the bucket index)
final K key;

// key → The element added to the HashSet

V value;

// value → A dummy constant object called PRESENT (used to

complete the key–value pair)


Node <K, V> next;
during collisions)

Page 204 of 214


Java Complete Study Notes | By Jatin Sir

// next → A pointer to the next node in the same bucket (used

}
How to Insert an Element Inside a
HashMap?
Syntax:
[Link](10, "java");
Internally, this calls:
public V put(K key, V value)
When we call [Link](10, "java"), it triggers the put(K key, V value) method defined in
the Map interface and implemented by the HashMap class.
The HashMap then calculates the hash code for the key, finds the correct bucket, and
stores the key-value pair as a Node in that location.
Step-by-Step Internal Process:
Step 1: Calculate the hash of the key
hash(10) = 10 // In Java, Integer's hashCode() returns the number itself
Step 2: Create a Node at bucket index 10.
BUCKET
+------+
+----------+----------+----------+----------+
| 10 | ──────────────► | hashCode | key
+------+
| 10
| 10
| java
| null
| value | next
+----------+----------+----------+----------
Inserting Another Key:
Why Modulus (or Bitwise AND)?
We often explain HashMap index calculation using %, because it's easy to understand.
Internally (in real HashMap source code): Java actually uses bitwise AND (&) instead of
% to keep the index within range (0 to 15)
hash & (n - 1) Where n = array length (e.g., 16) // instead of hash % size
32 & (16 - 1) = 32 & 15 = 0
Why Java Uses & Instead of %? Because & is much faster than %
HashMap always maintains its array size as a power of 2 (16, 32, etc.), so hash % size

Page 205 of 214


Java Complete Study Notes | By Jatin Sir

and hash & (size - 1) will always give the same result.
Collision Example
[Link](64, "RestAssured");
hash(64) = 64
64 % 16 = 0
Bucket index = 0, but index 0 already has key 32.
Both 32 and 64 are stored in the same bucket as a linked list chain >> Collision Occurs!
What is a Collision?
A collision happens when two different KEYS map to the same bucket index after
hashing.
In this case: Keys: 32 and 64
Same bucket: 0
What happens when collision occurs?
Collision will results in creating a linkedlist .
When multiple keys generate the same bucket index (after applying hash function),
Java handles this by creating a LINKEDLIST at that index.
Each new (key, value) pair is added as a NODE in the LinkedList.
BUCKET
+------+
+----------+----------+----------+----------+
| 0 | ──────────────► | hashCode | key
| value | next
+------+
|0
| 32
| python | ──┐
+----------+----------+----------+


+----------+----------+-------------+----------+
| hashCode | key
|0
| 64
| value
| next
| RestAssured | null
+----------+----------+----------+--------------+
How to retrieve value from Linkedlist ?

Page 206 of 214


Java Complete Study Notes | By Jatin Sir

[Link](64) // get the value of key 64


hash(64)= 64
64% 16 = 0
java goes to bucket 0, and check whether key 64 is present and return the value "
restAssured".
Is too many collisions good or bad?
Not good!
Collisions reduce the performance of HashMap by increasing the time to search, insert,
or delete entries.
What Happens When Collisions
Increase and How Java Handles It ?
> When multiple keys hash to the same bucket, they are stored in a LINKEDLIST.
> If the number of nodes in a bucket exceeds 8, Java (since version 8) converts the list
into a Red-Black Tree to improve performance.
• Tree lookup: O(log n)
• LinkedList lookup: O(n)
• DEFAULT LOAD FACTOR: 0.75 > This means when the number of entries exceeds
75% of the current capacity, the map will RESIZE (usually doubles the capacity).
> What happens during RESIZING ?
> A new, larger array is created.
> All existing entries are rehashed and rearranged to new buckets.
> This is called REHASHING, and it’s an EXPENSIVE operation in terms of
performance.
> Frequent resizing can lead to performance issues. That’s why choosing a good
initial capacity is important for large datasets.
How many null KEYS hashmap can
have?
Only one
How many null VALUES hashmap can
have?
Multiple
Who is the child of Hashmap?
Hashmap<String, String> name = new LinkedHashMap<String,String>()
LinkedHashMap extends HashMap > ie. LinkedHashmap is the child of hashmap
It inherits all behavior from HashMap but also maintains insertion order
We can use a LinkedHashMap object wherever a HashMap is expected — because of
inheritance and polymorphism.
Map Implementations Comparison

Page 207 of 214


Java Complete Study Notes | By Jatin Sir

What is the difference between


HashMap and Hashtable?
> HashMap is not thread-safe and non-synchronized.
>It should not be used in multithreaded environments without external synchronization
(e.g., [Link]() or ConcurrentHashMap).
> Hashtable is thread-safe and synchronized.
> Every method is synchronized, which makes it safe for concurrent access — but
slower in performance.
> HashMap allows one null key and multiple null values.
> Hashtable does not allow any null key or null values.
What if two keys have the same
hashCode()?
If two keys have the same hashCode(), HashMap uses .equals() to further check if they
are logically equal:
If .equals() returns false →
> Both keys are stored in the same bucket (collision is handled using a linked list or
tree)
If .equals() returns true →
> The existing value is replaced with the new one (duplicate key)
Commonly Used Methods in Java Map
public static void main(String[] args) {

// Create a HashMap with Integer as key and String as value

Map<Integer, String> employeeMap = new HashMap<>();

// put(key, value) → Adds entries to the map

[Link](101, "A");
[Link](102, "R");
[Link](103, "S");

// Adding a duplicate key replaces the old value

[Link](102, "C"); // replaces "R"

// Print entire map

[Link]("Employee Map: " + employeeMap);

Page 208 of 214


Java Complete Study Notes | By Jatin Sir

// Output: {101=A, 102=C, 103=S}

// get(key) → Retrieves the value associated with the key

[Link]("Get key 101: " + [Link](101)); // A


[Link]("Get key 999: " + [Link](999)); // null (key doesn't
exist)

// --------------------------------------// Internal hashing and bucket indexing

// ---------------------------------------

// Hash code calculation of keys (used internally to find bucket index)

// hashCode() returns a number used by Java to decide where to store the entry

[Link]("Hash of key 101: " + [Link](101).hashCode());

// To find the bucket index → Java does: hash % arraySize (usually 16 initially)

[Link]("101 % 16 (bucket index): " + (101 % 16));


[Link]("102 % 16 (bucket index): " + (102 % 16));
[Link]("103 % 16 (bucket index): " + (103 % 16));

// So keys 101, 102, and 103 are stored at different buckets based on the result

// keySet() → returns all keys in the map

Set<Integer> keySet = [Link]();


[Link]("All keys in employeeMap: " + keySet);

// entrySet() → for traversing all key-value pairs

[Link]("Traversing employeeMap:");
for ([Link]<Integer, String> entry : [Link]()) {

Page 209 of 214


Java Complete Study Notes | By Jatin Sir

[Link]([Link]() + " -----> " + [Link]());


}

// --------------------------------------// Case Sensitivity in Map keys

// ---------------------------------------

Map<String, String> studentMap = new HashMap<>();


[Link]("John", "Present");

// Case mismatch: returns null

[Link]("[Link]("john"): " + [Link]("john")); // null

// Correct key (case matched): returns value

[Link]("[Link]("John"): " + [Link]("John")); //


Present

// Map keys are case-sensitive!

// "John" and "john" are considered two different keys

}
}
Summary
| Method
| Purpose
| get(key)
| Retrieves the value for a given key
| keySet()
| Returns a Set of all keys
| entrySet()
Comparisons
(1) Local Variable Vs Instance Variable
| Feature
| Local Variable
| Instance Variable

Page 210 of 214


Java Complete Study Notes | By Jatin Sir

a class
| Declared inside a method or block
| Declared inside
| Scope
Accessible by all methods of the class (via object)
memory
| Stored in stack memory
| Stored in heap
| Default Value
| No default value, must be initialized before use
values (e.g., null, 0, false)
as the object exists
| Default
| Exists as long
| Access Modifier.
| No access modifier
modifiers (public, private, protected)
| Can have access
| Storage Location
(object)
| Stored in the heap
| Stored in the stack
| Connection to Heap.
| No connection to heap
variable in the stack points to the object in the heap
| Reference
------------------------------------------------------------------------------------------------------------------------------------
------------------------

// Instance variables declared inside class - reference variable (name,age,address) is

stored in stack and points to object (john,25,)in stack


public class Person {

// Instance variables with different access modifiers

private String name = "John"; // Private instance variable


public int age = 25;

Page 211 of 214


Java Complete Study Notes | By Jatin Sir

// Public instance variable

protected String address = "123 Main St"; // Protected instance variable

// Method to display local variable - stored in stack

public void displayInfo() {

// Local variable (no access modifier)//

int x = 10; // local variable

// Main method to run the program

public static void main(String[] args) {

// Creating an object of Person class

Person person = new Person();


}
}
+-------------------------------------------+
Stack - Local Variable
+-------------------------------------------+
+-------------------------------------------+
+-------------------------------------------+
+-------------------------------------------+
| Reference variable: person -> 0x12345
| Local variable: x = 10
Heap - Instance Variables
| ---> | Object: Person
| - name = "John"
| - age = 25
| - address = "123 Main St"
+-------------------------------------------+
| (The reference 'person' in the stack
| points to the memory address of the
| object in the heap)
+-------------------------------------------+

Page 212 of 214


Java Complete Study Notes | By Jatin Sir

Key points
Local variables must be explicitly initialized before they can be accessed. If they are not
initialized, trying to access them will lead to a compiler error.
Instance variables do not require initialization explicitly, they will be initialized to default
values when the object is created.
int x; // Declaring local variable without initializing
[Link](x); // Error: variable x might not have been initialized
(2) Constructors Vs Setters
Constructor
Setter
Special method with the SAME NAME

AS CLASS
NORMAL METHOD follows
camelCase naming.
Has NO RETURN TYPE
Has a return type (commonly void).
Called ONCE during object creation.
Can be called multiple times after
object creation.
Used to INITIALIZE instance variables.
Used to UPDATE/CHANGE
instance variables.
If only constructors are used → object
is Immutable (values fixed after
creation).
Using setters makes object Mutable
(values can be updated).
Can be overloaded (multiple
constructors with different parameters).
Setters are not overloaded, but
multiple setters exist (one per
variable).
Values are assigned only once when
the object is created.
Values can be updated any number
of times.
class Person {
String name;

Page 213 of 214


Java Complete Study Notes | By Jatin Sir

Person(String name) {

Page 214 of 214

You might also like