0% found this document useful (0 votes)
4 views132 pages

Java Back End Dev

The document provides a comprehensive overview of Java installation, CPU architecture, memory types, operating systems, programming languages, and their features. It explains the differences between microcontrollers and microprocessors, as well as the roles of JDK, JRE, and JVM in Java programming. Additionally, it discusses Java's characteristics, such as platform independence, security, and multithreading capabilities.

Uploaded by

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

Java Back End Dev

The document provides a comprehensive overview of Java installation, CPU architecture, memory types, operating systems, programming languages, and their features. It explains the differences between microcontrollers and microprocessors, as well as the roles of JDK, JRE, and JVM in Java programming. Additionally, it discusses Java's characteristics, such as platform independence, security, and multithreading capabilities.

Uploaded by

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

Installing JDK

 Install JDK (Java Development Kit) → for compiling & running code,
and JRE (Java Runtime Environment) → for running only
(Most developers install the JDK, which already includes the JRE.)
 Check if Java is already installed or not:
java -version
openjdk version "21.0.8" 2025-07-15
OpenJDK Runtime Environment (build 21.0.8+9-Ubuntu-0ubuntu124.04.1)
OpenJDK 64-Bit Server VM (build 21.0.8+9-Ubuntu-0ubuntu124.04.1, mixed mode, sharing)
 javac -version
javac 21.0.8
 Install OpenJDK (Ubuntu provides OpenJDK via apt)
 Java 21 (latest LTS-Long Term Support)
sudo apt update
sudo apt install openjdk-21-jdk -y
 sudo update-alternatives --config java
/usr/lib/jvm/java-21-openjdk-amd64/bin/java
 nano [Link] # file creation for small java program
 javac [Link] # compiles to [Link]
 java HelloWorld # runs the compiled class

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

CPU (Central Processing Unit)

 Brain of the computer - performs all calculations, executes instructions, and controls all other parts of the system.
Main Components of CPU
ALU (Arithmetic Logic Unit) Performs arithmetic operations and logical operations (like
comparison).
CU (Control Unit) Controls and coordinates the activities of all parts of the
computer - fetches, decodes, and executes instructions.
Registers Small, high-speed storage locations inside the CPU used to
store temporary data and instructions.

 Functions:
◦ Fetches instructions from memory.
◦ Decodes and executes them.
◦ Sends output to the appropriate device.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Memory (Storage Unit)


 Part of the computer that stores data and instructions for processing.
Types of Memory
Primary Memory Directly accessible by CPU; RAM, ROM, Cache
Stores data temporarily or permanently.
Secondary Memory Used for long-term storage of data and Hard Disk Drive (HDD), Solid State Drive
programs. (SSD), Pend Drive, CD/DVD, Memory
Card

Primary Memory Types


RAM (Random Access Temporary memory - data is lost when power is off. Used for running
Memory) programs.
ROM (Read Only Memory) Permanent memory - stores system instructions like BIOS.
Cache memory Very fast memory between CPU and RAM; speeds up processing

 Input → CPU (Process) ↔ Memory (Store) → Output


The CPU fetches data from memory, processes it, and stores results back in memory before sending it to an output device.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Operating System
 System software - acts as an interface between the user and the computer hardware. It manages all hardware and software
resources and allows other programs to run.
 Functions:
◦ Process Management: Manages running programs (processes), their execution, and CPU scheduling.
◦ Memory Management: Allocates and tracks computer memory (RAM) used by programs.
◦ File Management: Manages files - how data us stored, named, and retrieved from storage devices.
◦ Device Management: Controls and coordinates I/O devices.
◦ User Interface (UI): Provides a way for users to interact with the computer. Eg., Command line (CLI) or GUI.
◦ Security & Access Control: Protects system data from unauthorized access or misuse.
◦ Error Detection & Handling: Detects and handles errors in software or hardware during operations.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Programming Language

 Set of instructions and rules - allows humans to communicate with a computer to create software, websites, and applications.
 It acts as a bridge between humans and machines, translating human logic into machine-understandable form (binary code or
sequence 0101).

Programming Language Types


Machine Language Lowest-level language written in binary (0s and 10110000 011000001
1s) that CPU can directly understand.
Assembly Language Uses short symbolic codes (mnemonics) instead MOV A, B
of binary. Needs an assembler to convert it into
machine code.
High Level Language Closer to human language; easy to read, write, C, C++, Java, Python, Javascript
and debug. Needs a compiler or interpreter to
translate into machine code.

High Level Languages Categories

Procedural Language Programs written as a series of steps or C, Pascal


procedures. Top to Bottom Approach
Object-Oriented Organize programs using objects (data + Java, C++, Python
Languages (OOP) functions). Bottom to Top Approach
Functional Language Focus on functions and mathematical logic. Lisp, Haskell
Scripting Languages Used for automation or web scripting Javascript, PHP, Python
Markup Language Used to format and present data. HTML, XML

Low-Level Language A language that is close to machine language Machine Language, Assembly
(binary code) and provides little to no Language
abstraction from hardware(giving more over
hardware but harder to write).
Directly understandable by the computer with
minimal translation.
Mid-Level Language A language that bridges the gap between C (You can use it for system
machine and high-level languages. Supports both programming - like kernel
low-level (hardware access) and high-level development, and can also
(programming logic) features. make applications)
High Level Language Human-readable and are portable across C++, Java, Python, Javascript,
computers. And also provides abstraction from PHP, C#
hardware. They need a compiler or interpreter to
run.
Programming Language Methodology
 Structured approach used to design, organize, and develop programs using a particular language.
 It’s how you plan, structure, and write your code to solve problems efficiently and maintainably.
Cross-Cutting Concerns
 Java is NOT a Pure Object-Oriented Programming
◦ A pure object-oriented programming language is one in which everything is an object – every value, variable, operation, and
data type must belong to some class or object.
◦ In pure OOP language:
▪ NO primitive data types (everything is an object)
▪ Everything is accessed via methods
▪ There are no standalone functions or variables
▪ All code resides inside classes or objects
▪ Smalltalk – example of a nearly pure OOP language – even numbers, booleans, and operators is an object.
◦ Java is object-oriented, but NOT purely object-oriented. It follows most OOP principles but still allows some non-object-
oriented features.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Assembler vs Compiler vs Interpreter


 All three are language translators. Their job is to convert human-readable code into machine language (binary 0s and 1s) that the
computer can execute.
 Assembler
 Translates assembly language (low-level code close to machine language).
 Assembly Language → Assembler → Machine Code

 Compiler
◦ Translates the entire program written in a high-level language (HLL) (like C, C++, Java) into machine code (object code or
executable file) before execution.
◦ High-Level Language → Compiler → Machine Code / Object Code

 Interpreter
◦ An interpreter translates and executes the program line-by-line (or statement-by-statement) at runtime.
◦ High-Level Language → Interpreter → Execution (immediate)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
C++ vs Java

 Sun Microsystems designed Java (1995) with one main goal:


✅ “Make a simpler, safer, portable, and platform-independent version of C++.” So, Java took inspiration from C++ but
removed many of its complexities.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Platform

 The environment in which a program runs.

 It includes both:
◦ Hardware: the physical machine (CPU, memory)
◦ Software: the operating system and runtime that manage and execute programs.
 When we talk about Java, the term “platform” means something very specific:
Java Platform = Java Runtime Environment (JRE) + Java Development Kit (JDK) + JVM + Java API
In short, Java provides its own platform, which runs on top of other platforms (like Windows, Linux, macOS). That’s what makes Java
platform-independent.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Microcontroller vs Microprocessor

 Both microcontroller and microprocessor are integrated circuits (ICs) that act as the brain of a computing system. (Hardware)

 Microprocessor (MPU)
◦ Brain Only
◦ A CPU chip used in general-purpose computers or systems where high computing power is needed.
◦ It only contains ALU (Arithmetic Logic Unit), Control Unit, and Registers
◦ It needs external chips for memory (RAM/ROM), Input/Output ports, Timers, ADCs, etc.
◦ Eg., Intel Core i7, AMD Ryzen, Intel 8085, Pentium.
◦ Used in desktop PCs, laptops, servers, high-performance systems.
 Microcontroller (MCU)
◦ Brain + Body
◦ A self-contained mini-computer on a single chip.
◦ It includes CPU, RAM, ROM/Flash memory, Input/Output ports, Timers, Counters, ADC (Analog-to-Digital Converter), and
Communication interfaces (UART, SPI, I2C).
◦ Eg., Intel 8051, PIC, Atmega328 (Arduino), ARM Cortex-M series, ESP32.
◦ Used in Embedded systems, Home appliances, Cars (engine control, sensors), Robotics, IoT devices, Washing machines, and
Microwave ovens.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Features of Java

Simple Java is easy to learn and use because it has clear syntax and easy to understand. It does NOT have
complex features like pointers, operator overloading, multiple inheritance, and explicit memory
allocation. There is NO need to remove unreferenced objects because there is an automatic memory
management (Garbage Collection).
Object-Oriented Everything in Java is treated as object - making code modular, reusable, and easier to maintain.
Java is a very object-oriented language. Object-oriented means we organise our software as a
combination of different types of objects that incorporate both data and behavior (Whatever the logic
we want to write for our application, it will be written in the form of objects and class).
It follows concepts like Inheritance, Polymorphism, Abstraction, and Encapsulation.
Platform Independent and Compiler converts source code to bytecode and then the JVM executes the bytecode generated by the
Portable compiler. This bytecode can run on any platform be it Windows, Linux, or macOS, which means if we
compile a program on Windows, then we can run it on Linux and vice versa. Each operating system has
a different JVM, but the output produced by all the OS is the same after the execution of bytecode. It is
a software-based platform that runs on top of other hardware-based platforms which has two
components: Runtime Environment & Application Programming Interface.
Secured Java provides strong security features like bytecode verification, no explicit pointers, and a security
manager that defines access rules for classes.
[In Java, we do NOT have pointers, so we can NOT access out-of-bound arrays. That’s why several
security flaws like stack corruption or buffer overflow are impossible to exploit in Java. Also, Java
programs run in an environment (JVM) that is independent of the OS (Operating System) environment
which makes java programs more secure. Class Loader adds security by separating the package for the
classes of the local file system from those that are imported from network sources. Bytecode Verifier
checks the code fragments for illegal code that can violate access rights to objects. Security Manager
determines what resources a class can access such as reading and writing to the local disk.]
Robust Java language is robust which means reliable. It is developed in such a way that it puts a lot of effort
into checking errors as early as possible, that’s why the Java compiler can detect even those errors that
are not easy to detect any other programming language. Java has strong error-handling, exception
management, and memory management, reducing the chance of system crashes.
High Performance Java uses Just-In-Time (JIT) compiler (part of JVM).
When you run Java program, the Java compiler first converts .java into bytecode .class. JVM loads
bytecode and JIT compiler translates frequently executed parts (called hot code) into native machine
code at runtime. Once converted, this native code runs directly on the CPU, which makes execution
much faster.
Dynamic The Class Loader in Java loads new classes dynamically into memory while the program is running.
The Reflection API allows inspection and modification of classes, methods, and objects during runtime.
[In a web application, when a new plugin or module is added, Java doesn’t need to recompile the entire
program - it can load the new class dynamically while the application is running.]
Power of compilation and Most languages are designed with purpose either they are compiled language or they are interpreted
interpretation language. But Java integrates arising enormous power as Java compiler compiles the source code to
bytecode and JVM executes this bytecode to machine OS-dependent executable code.
Snadbox Execution Java programs run in a separate space that allows user to execute their applications without affecting
the underlying system with the help of a bytecode verifier.
Distributed Java enables programs to run and communicate across multiple networked systems. e.g., RMI (Remote
Method Invocation), EJB (Enterprise Java Beans), network-based apps.
[Java provides built-in networking APIs ([Link] package) to handle data exchange over the internet or
LAN.
Technologies like RMI and EJB allow objects or components to communicate and work together even if
they are on different machines.
Suppose you have a banking system where the front-end runs on one computer and the database on
another. Java can connect both using RMI, allowing one system to call methods or functions stores on
the other system - as if they were local.]
Multithreaded We can write Java programs that deal with many tasks at once by defining multiple threads for
maximum utilization of the CPU. The main advantage of multi-threading is that it doesn’t occupy
memory for each thread. It shares a common memory area. Threads are important for multi-media,
web applications, etc.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

JDK, JRE, JVM


 JDK: (Java Development Kit) is a Kit that provides the environment to develop and execute (run) the Java program. JDK is a kit (or
package) that includes two things:
◦ Development Tools (to provide the environment to develop your java programs), and
◦ JRE (to execute your java program)
◦ JDK = JRE + Development Tools

 JRE: (Java Runtime Environment) is an installation package that provides an environment to only run (not develop) the java program
(or application) onto your machine. JRE is only used by those who only want to run Java programs that are end-users of your system.
It contains JVM, Core libraries (like [Link], [Link], [Link]), Runtime files.

 JVM is the engine that actually runs your Java programs.


◦ JVM is very important part of both JDK and JRE because it is contained or inbuilt in both. Whatever Java program you run using
JRE or JDK goes into JVM and JVM is responsible for executing the java program line by line, hence it is also known as an
intepreter.
◦ JVM becomes an instance of JRE at the runtime of a Java program. It is widely known as a runtime interpreter. JVM largely
helps in the abstraction of inner implementation from the programmers who make use of libraries for their programs from JDK.
◦ It is mainly responsible for three activities: Loading, Linking and Initialization - often referred to as the Class Lifecycle inside the
Java Virtual Machine.
▪ Loading: The JVM loads the class file into memory.
 Who does it: Class Loader subsystem (Bootstrap, Extension, Application class loaders).
 Reads the binary class data from file, network, or any source.
 Creates an in-memory representation of the class in the Method Area.
 Assigns a unique Class object (in the Heap) for that metadata.
▪ Linking: Linking ensures the loaded class is ready to execute. It has three substeps:
 Verification: Checks whether the bytecode is structurally valid. Ensures no illegal operations (e.g., stack overflows,
illegal type conversion). Prevents JVM crashes → key to Java’s security.
 Preparation: Allocates memory for static variables. Sets default values (0, null, false, etc.). Note: No explicit
initialization values yet.
 Resolution: Converts symbolic references in the class file into direct references. Example: converting a method name
“java/lang/System” into a direct pointer in memory.
▪ Initialization: This is where actual code runs.
 Executes static variable initializers.
 Executes static blocks in the order they appear.
 Performs any initialization needed before object creation.
◦ JVM acts as a run-time engine to run Java applications. JVM is the one that actually calls the main method present in Java code.
JVM is a part of JRE.
◦ Java applications are called WORA (Write Once Run Anywhere). This means a programmer can develop Java code on one
system and can expect it to run on any other Java-enabled system without any adjustments. This is all possible because of JVM.
◦ When we compile a .java file, .class files (contains byte-code) with the same class names present in .java file are generated by
the Java compiler. This .class file goes into various steps when we run it. These steps together describe the whole JVM.
▪ JVM is responsible for loading .class files (bytecode), verifying the code (for security), converting bytecode to machine
code (using JIT Compiler), managing memory (via Garbage Collector), providing a runtime environment.

 The entry point of your Java program is the main method. The JVM always looks for main method to start execution.
◦ Another method inside your class will not get displayed. JVM does not call it automatically because the method is the only one
executed by default.
◦ To execute it, you must call it manually inside main().
public class Basic {
public static void main(String[] args) {
[Link]("Hello World!");
}

public static void ImpotantMethod(String[] args) {


[Link]("Hello World 2!");
}
}
Correct way to do it:
You can define your own methods (or custom methods) and call them from main().

public static void main(String[] args) {


[Link]("Hello World!");
ImportantMethod(args);
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

How to create a program in any programming language

 With IDE (Integrated Development Environment) – Eclipse, Net Beans, IntelliJIDEA


 Without IDE – Editor + Compiler + Lib

 Source code ([Link]) written in C or C++. It is human-readable, but hardware cannot understand this directly.
 The Compiler (gcc or g++) translates source code into machine code. The compiler checks syntax errors, type errors, and linking of
functions. If everything is correct, it generates an executable file.
 Output: [Link] (on Windows) or [Link] (on Linux). This file contains machine instructions the CPU can execute.
 When you run [Link], it is loaded into memory by the OS. The OS communicates with the hardware to execute instructions. The
output is then displayed on the screen.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

JShell
 An interactive tool introduced in Java 9 - allows developers to execute Java code snippets instantly, without creating a full Java class
or writing boilerplate code like
public static void main(String[] args)
 Also known as Java REPL (Read Eval Print Loop) - a command line tool for testing, learning, and exploring Java interactively.
 How to start JShell?
◦ Open command prompt or terminal
◦ Type jshell
◦ Type syntax to check
◦ Exit JShell using /exit.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Running Java Program

 Writing the Program


 You write Java code in a file with .java extension. This file is source code written in human-readable form.
 Compilation (Source code -> Bytecode)
 You use Java Compiler (javac) to compile your rograms.
 This creates a file named [Link]. This .class file contains bytecode - an intermediate form of your code that is not specific
to any computer. It’s platform-independent and can run on any system with a Java Virtual Machine (JVM).
 Class Loader (Loading Bytecode into JVM)
 When you run the program, the JVM’s Class Loader loads the .class file into memory. It loads:
 The main class you’re running (HelloWorld)
 Other classes that it depends on (like System class)
 Bytecode Verification
 Before executing, the Bytecode Verifier checks the bytecode for security and correctness:
 Ensures no illegal code is executed (e.g., accessing private memory)
 Prevents harmful operations
 Execution by JVM (Interpreter + JIT Compiler)
 When you run java HelloWorld
 The JVM starts executing your bytecode:
 Interpreter reads and executes bytecode line by line.
 JIT (Just-In-Time) Compiler improves performance by converting frequently used bytecode into native machine code (specific to
your CPU).
 Thus, your program runs efficiently and safely across different platforms.
 Output Display
 Finally, JVM prints the result on the console.
 Why Java is called a Platform?
◦ A platform is any environment in which programs can run.
◦ Java provides not only a programming language but also its own runtime environment and APIs — so together, they form a
complete platform.

 Java is used in all kinds of applications like mobile applications (Android is Java-based), desktop applications, web applications, client-
server applications, enterprise applications, gaming applications, cloud-based applications, and many more in all domain.
◦ Eg., Spotify, Twitter, Opera Mini Browser, Acrobat Reader, Netflix, Uber, MatLab, Simcards, Fintech Domain (Barclays, Hsbc, Citi
group, Goldman Sachs), Eclipse, Hadoop, Google Docs, etc.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Comments

 Comments are non-executable statements used to explain code. They help developers understand, maintain, and document
programs — they are ignored by the compiler.

 Use comments to explain why, not just what.


 Keep comments updated with code changes.
 Avoid over-commenting trivial lines.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

public static void main(String[] args)

 Standard main method: public static void main(String[] args)


◦ This is the entry point of a standalone Java application. The JVM looks specially for this method using reflection.
 If the main method is declared protected instead of public, the program will compile but will NOT run.
◦ protected limits access to only within the same package OR subclasses.
 What exact signature must stay the same?
◦ For the JVM to recognize it as the entry point, the method must be:
▪ public
▪ static
▪ void
▪ Named exactly main
▪ Accept one parameter
▪ Parameter type must be String[] (array of String)
▪ Parameter can have any valid identifier name
▪ May optionally include throws clause
 Valid JVM-recognized signatures:
◦ public static void main(String[] args)
◦ public static void main(String args[])
◦ public static void main(String[] a) - parameter name can be anything (a, xyz, etc)
◦ public static void main(String… args)
◦ public static void main(String[] args) throws Exception
◦ static public void main(String... anything) - Order of public static can be swapped
 Meaning of each keyword:
◦ public
▪ Accessible from anywhere
▪ JVM is outside your class. It must be able to access the method.
▪ If public removed: This would result in Runtime error “Error: Main method not found in class”. Because JVM cannot
access non-public method.
◦ static
▪ Belongs to the class, not to an object.
▪ JVM starts execution without creating an object of your class.
▪ If static is removed: JVM error “Error: Main method is not static in class”. Because JVM cannot call instance methods
without object.
◦ void
▪ Method does NOT return anything.
▪ JVM does NOT expect any return value.
▪ If changed to int: Compilation succeeds, but JVM gives “Error: Main method must return a value of type void”.
◦ main
▪ Special method name hardcoded in JVM specification.
▪ If renamed start: JVM error “Error: Main method not found in class”. Because JVM specifically searches for method
named main.
◦ String[] args
▪ Array of Strings passed from command-line arguments.
 Eg., java MyProgram hello world -> args[0] = “hello”, args[1] = “world”
▪ If parameter is changed to int[] args: JVM error “Error: Main method not found”. Because JVM expects String[].
▪ If no parameters passed: public static void main() would NOT be recognized by JVM.
 Overloading main()
◦ You can overload public static void main(String[] args) with public static void main(int x). But JVM will only call public static void
main(String[] args)
 Fully qualified type is used internally public static void main([Link][])

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

[Link]()

 This is not a single function. It is a chain of Class, Static field, Object, and Method call.
 Break it into components:
◦ System
▪ System is a class in [Link]. So internally it is [Link]. It is automatically imported because [Link].* is
imported by default.
◦ out
▪ Inside System class, there is a field public static final PrintStream out;
▪ Meaning
 public → accessible everywhere
 static → belongs to class, not object
 final → reference cannot change
 Type = PrintStream
▪ So [Link] means access static variable out inside class System.
▪ out is an object of class [Link]. So, [Link] returns a PrintStream object.
◦ println()
▪ println() is a method inside PrintStream. So, [Link]() means call println() method on the PrintStream object
stored in [Link].
◦ println() is the method of the PrintStream class; out is an object of PrintStream which is present inside the System class.
 Technical Structure:
Variable Naming
 Valid variable names: ab, AB, aBc, a1, a12, _a, a_b, ab$, $ab

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Data Types

Primitive Data Types

Data Type Description Range


byte 1 byte -27 to 27-1 (-128 to 127)
short 2 byte -215 to 215-1 (-32k to 32k)
int 4 byte -231 to 231-1 (-2b to 2b)
long 8 bytes (64-bit signed) -263 to 263-1
float 4 bytes (32-bit floating pt) -2149 to 2127
double 8 bytes (64-bit floating pt) -21074 to 21023
char 2 bytes (16-bit unsigned) 0 to 216
boolean 1 byte true/false

 1 byte of space would store 8 bits of data. Out of which one is used for sign

public class PrimitiveDataTypes {


public static void main(String[] args) {

byte byteMin = -128;


byte byteMax = 127;

short shortMin = -32768;


short shortMax = 32767;

int num = 5;
// int num2 = 5.5; // incompatible types: possible lossy conversion from double to int
// int num3 = 9999999999999999; // integer number too large

long longMin = -9223372036854775808L;


long longMax = 9223372036854775807L;

float floatValue = 5.07f;


// float floatValue2 = 5.0777; // incompatible types: possible lossy conversion from double to float

double doubleValue = 0.548;

char uppercaseChar = 'C';


char lowercaseChar = 'm';

boolean value = true;


}
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Format Specifiers
 % is used as a placeholder that tells the compiler: the value to be printed is of this specific data type. These placeholders are called
format specifiers.
◦ A convenience method to write a formatted string to this output stream using the specified format string and arguments.
An invocation of this method of the form [Link](format, args).
public class PrimitiveDataType1 {
public static void main(String[] args) {

byte byteMin = -128;


[Link]("Byte minimum value = %d", byteMin);
short shortMin = -32768;
[Link]("Short minimum value = %d", shortMin);

int num = 5;
[Link]("Number = %d", num);

long longMin = -9223372036854775808L;


long longMax = 9223372036854775807L;
[Link]("Maximum long value = %d",longMax);
[Link]("Minimum long value = %l", longMin);

float pi = 3.14159f;
[Link]("Pi = %.2f", pi);

double doubleValue = 0.548;


[Link]("Double value = %f", doubleValue);

char ch = 'A';
[Link]("Character = %c", ch);

boolean result = true;


[Link]("Boolean value = %b", result);

String name = "Satyam";


[Link]("Name = %s", name);

[Link]("Success = 90%%"); // PERCENTAGE SYMBOL

// MULTIPLE VALUES TOGETHER


int age = 22;
double marks = 85.5;
char grade = 'A';
[Link](
"Age: %d, Marks: %.1f, Grade: %c",
age, marks, grade
);

}
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Primitive vs Non-Primitive (Reference) Data Types


 The Reference Data Types will contain a memory address of variable values because the reference types won’t store the variable
value directly in memory. They are strings, objects, arrays, etc.
Primitive Data Types Non-Primitive Data Types
Store the actual value directly in memory. Store the memory address (reference) of the
int a = 10; object, not the actual value.
char c = 'A'; String s = "Java";
boolean flag = true; int[] arr = {1,2,3};
Student obj = new Student();
Definition Built-in types like int, char User-defined or library types like String, Array,
Primitive → simple values Class
Reference → objects
Memory Location Stored directly in stack memory. Reference in stack, actual object in heap.
int x = 10; // value stored in stack String s = "Hi"; // s → stack, "Hi" → heap
Size Fixed size Variable size
int → always 4 bytes String → size depends on characters
Overhead No overhead. Objects need memory for data, methods, and
JVM metadata.
Garbage Collection Primitive values are destroyed automatically Objects are cleaned by GC when no reference
when method ends. exists.
Nullability Cannot be null. Can be null.
int x = null; // ❌ Error String s = null; // ✅ Allowed
Obect Nature Not objects. Are objects (Only objects can have methods, and
properties).
Performance Faster. Slightly slower.
Primitive → direct access Reference → heap + pointer access
Pass-by Behavior Passed by value (actual data). Passed by value (reference copy).
void change(int x) { x = 20; } // original not void changeObj(Student s) { [Link]=5;} // object
changed data changes
Caching/Pooling
Method Availability No methods. Have methods.
int x = 10; String s = "Java";
[Link](); // ❌ [Link](); // ✅
Use in Collections Not allowed directly (Wrapper classes are Allowed
needed for primitives). ArrayList<Integer> list; // ✅
ArrayList<int> list; // ❌

 Non-Primitive demonstration

class Point {
int x;
int y;
}

class Test {
public static void main(String[] args) {

Point p1 = new Point(); // Object creation


p1.x = 10;
p1.y = 20;

Point p2 = p1; // IMPORTANT LINE


p2.x = 30;

[Link](p1.x); // 30
[Link](p2.x); // 30
}
}

◦ Data type that any class creates is non-primitive data type.


◦ We create variables of non-primitive type using new keyword. We access the members of a non-primitive variable using dot
operator. So, if you want to access x, you need to use p.x
◦ Non-primitive variables are always references (just hold a reference to the memory location where this object is stored). In this
code, p1 variable holds a reference to the memory X and y with the values 10 and 20.
◦ What is really happening in memory?
▪ Point p1 = new Point();
A Point object is ceated in heap memory.
p1 stores the reference (address) to that object
Heap:
[ Point object ]
x = 10
y = 20
p1 ─────► Point object
▪ Reference copy (NOT object copy)
Point p2 = p1;
No new object is created
p2 now points to the same object as p1
p1 ─┐
├──► [ Point object ]
p2 ─┘ x = 10
y = 20
This is called aliasing.
▪ Modify through p2
p2.x = 30;
Since both references point to the same object:
[ Point object ]
x = 30
y = 20
 What will be the output of this program?
class Point {
int x;
int y;
}
class Test {
static void main() {
Point p1 = new Point();
[Link](p1.x);
[Link](p1.y);
}
}

Output:
00

Explanation:
A Point object is created. And instance variables x and y are not explicitly initialized.

 What will be the output of this program?


class Test {
static void main() {
int x;
[Link](x);
}
}

Output:
Compile-time error: variable ‘x’ might not have been finalized.

 Swap two numbers


class SwapTwoNumbers {
static void main() {
int a = 10;
int b = 20;
a = b;
b = a;
[Link](a+" "+b);
}
}

Output:
20 20

class SwapTwoNumbers {
static void main() {
int a = 10;
int b = 20;
int temp = a;
a = b;
b = temp;
[Link](a+" "+b);
}
}

Output:
20 10


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Autoboxing and Unboxing


 Autoboxing: Automatic conversion of primitive -> wrapper object. Eg., Integer x2 = x1;
 Unboxing: Automatic conversion of wrapper object -> primitive Eg., int x3 = x2;

 What is the output of this program?


class Test {
static void main() {
int x1 = 10;
Integer x2 = x1;
int x3 = x2;
[Link](x1);
[Link](x2);
[Link](x3);
}
}

Output:
10 10 10

Explanation:
x1 is a primitive int
Autoboxing: primtive int -> wrapper class Integer
Uncoxing: Integer -> primitive int

 What is the output of this program?


class Test {
static void main() {
Integer x1 = 400;
int x2 = 400;
if(x1 == x2)
[Link]("Same");
else
[Link]("Not Same");
}
}

Output:
Not same

class Test {
static void main() {
Integer x1 = 40;
int x2 = 40;
if(x1 == x2)
[Link]("Same");
else
[Link]("Not Same");
}
}



---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Variables
 Variable in Java is a data container that saves the data values during Java program execution. Every variable is assigned a data type
that designates the type and quantity of value it can hold. A variable is a memory location name for the data.
 The value stored in a variable can be changed during program execution.
 In Java, all variables must be declared before use.
 Local Variables
◦ Defined within a block or method or constructor.
◦ The scope of these variables exists only within the block in which the variables are declared.
◦ Stored in stack memory.
◦ Must be initialized.
◦ Can NOT use access modifiers (public, private, etc.)
◦ Exists only during method execution.
class Test {
void display() {
int a = 10; // Local variable
[Link](a);
}
}

 Instance Variables
◦ Non-static variables and are declared in a class outside of any method, constructor, or block.
◦ They are declared in a class, these variables are created when an object of the class is created and destroyed when the object
is destroyed.
◦ Initialization is not mandatory(default 0).
◦ Can be accessed only by creating Objects.
◦ The scope of these variables available to all methods of that class.
◦ Stored in heap memory.
◦ Java assigns default value. [eg., int → 0, boolean → false, object → null]
class Student {
int age; // Instance variable

void show() {
[Link](age);
}
}
◦ Each object has its own copy.
◦ Changes in one object do NOT affect another.
Student s1 = new Student();
Student s2 = new Student();

[Link] = 20;
[Link] = 25;

 Static Variables
◦ Declared using the static keyword within a class outside of any method, constructor or block.
◦ Static variables are created at the start of program execution and destroyed automatically when execution ends.
◦ We can only have one copy of a static variable per class. Can be accessed without Object Creation. [When i declare the variable
static,there is a single copy of that variable created across class. So, even if I create 100 objects, 100 instance variables will be
created, but only a single static variable will be created.]
class Counter {

// Static variable (shared by all)


static int count = 0;

Counter() {
count++;
}

void display() {
[Link]("Count = " + count);
}

public static void main(String[] args) {

// Access static variable without object


[Link]("Initial Count: " + [Link]);

Counter c1 = new Counter();


Counter c2 = new Counter();
Counter c3 = new Counter();

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

// Access again without object


[Link]("Final Count: " + [Link]);
}
}
Output
Initial Count: 0
Count = 3
Count = 3
Count = 3
Final Count: 3

Explanation
static int count → Only one copy exists in the class.
Every time an object is created, the constructor increases count.
All objects share the same variable, so each prints the same value.
[Link] shows that static variables can be accessed without object creation.
◦ Shared among all objects.
◦ Stored in method area.
class Student {
static String college = "ABC College"; // Static variable
int id;

void display() {
[Link](id + " " + college);
}
}

Student s1 = new Student();


Student s2 = new Student();

[Link] = 1;
[Link] = 2;

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

Output
1 ABC College
1 ABC College

 Practical implementation:
◦ Local Variable
▪ Use a local variable when the data is temporary and only required during the execution of a method.
▪ Eg., Suppose we want to calculate the total price of items in a cart.
class Order {

void calculateTotal() {
int total = 0; // local variable

int[] prices = {100, 200, 150};

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


total = total + prices[i];
}

[Link]("Total Price: " + total);


}

public static void main(String[] args) {


Order order = new Order();
[Link]();
}
}

Why Local Variable Here?


total is needed only while calculating the sum.
Once the method finishes, the variable has no use.
Storing it as an instance variable would waste memory.

◦ Instance Variable
▪ Use instance variables when the data belongs to an object and every object should have its own value.
▪ Eg., student name, Bank account balance, Employee salary, Product price
class Student {

String name; // instance variable


int marks; // instance variable

void display() {
[Link](name + " scored " + marks);
}

public static void main(String[] args) {

Student s1 = new Student();


[Link] = "Rahul";
[Link] = 85;

Student s2 = new Student();


[Link] = "Aman";
[Link] = 90;

[Link]();
[Link]();
}
}

Why Instance Variable Here?


Every student has different marks and names.
Each object must store its own values.

◦ Static Variable
▪ Use static variables when the value is shared by all objects of the class.
▪ Eg., College name for students, Company name for employees, Bank name for all accounts, Global counter.
class Employee {

int id;
String name;
static String company = "TCS"; // static variable

void display() {
[Link](id + " " + name + " " + company);
}

public static void main(String[] args) {

Employee e1 = new Employee();


[Link] = 1;
[Link] = "Satyam";

Employee e2 = new Employee();


[Link] = 2;
[Link] = "Ravi";

[Link]();
[Link]();
}
}

Why Static Variable Here?


All employees belong to the same company.
Creating separate copies would be unnecessary.

Operators
 An operator is a symbol that performs an operation on one or more operands (variables or values) and produces a result.
int a = 10;
int b = 5;
int c = a + b; // '+' is an operator

Here,
a and b → operands
+ → operator
Result → 15

 Arithmetic Operators
◦ Used to perform mathematical calculations.

int a = 10;
int b = 3;

[Link](a + b); // 13
[Link](a - b); // 7
[Link](a * b); // 30
[Link](a / b); // 3
[Link](a % b); // 1

 Relational (or Comparison) Operators


◦ Used to compare two values.
◦ The result is always boolean (true/false).

int a = 10;
int b = 5;
[Link](a > b); // true
[Link](a == b); // false
[Link](a != b); // true

 Logical Operators
◦ Used with boolean expressions.

int age = 20;

[Link](age > 18 && age < 30); // true


[Link](age > 18 || age < 10); // true
[Link](!(age > 18)); // false

 Assignment Operators
◦ Used to assign values to variables.

int a = 10;
a += 5;

[Link](a); // 15

 Unary Operators
◦ Operate on only one operand.

int a = 5;

a++; // increment
[Link](a); // 6

a--; // decrement
[Link](a); // 5

 Bitwise Operators
◦ Used to perform bit-level operations.(Biwise operators work at the binary or bit level)
◦ Every integer in Java is stored as bits (0 and 1), and these operators manipulate those bits directly.
int a = 5; // 0101
int b = 3; // 0011

int result = a & b;


[Link](result); // 1

0101
&0011
-----
0001

int a = 5; // 0101
int b = 3; // 0011

int result = a | b;
[Link](result); // 7

0101
|0011
-----
0111
int a = 5; // 0101
int b = 3; // 0011

int result = a ^ b;
[Link](result); // 6

0101
^0011
-----
0110

int a = 5; // 0101
int result = ~a;

[Link](result); // -6

Binary (32-bit concept simplified):


5 = 00000000 00000000 00000000 00000101
~5 = 11111111 11111111 11111111 11111010

~x = -(x + 1)
~5 = -(5 + 1) = -6

iint a = 5;
int result = a << 1;

[Link](result); // 10

5 = 0101
0101 << 1
1010
int a = 8;
int result = a >> 1;

[Link](result); // 4

8 = 1000
1000 >> 1
0100

int a = -8;
int result = a >>> 1;

[Link](result);

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Access Modifiers
 Access modifiers in Java helps to restrict the scope of a class, constructor variable, method, or data member. There are four types
of access modifiers available in Java (i.e., public, protected, default, private).
 Accessibility: Private < Default < Protected < Public (most restricted → most open)

 Default
◦ In Java, default access modifier means no modifier is written. If you do not specify public, protected, or private, Java
automatically assigns default (package-private) access.
◦ Members with default access are accessible only within the same package.
class Student {

int age = 20; // default access

void display() { // default access


[Link]("Age: " + age);
}
}

class Main {

public static void main(String[] args) {

Student s = new Student();

[Link]([Link]); // allowed
[Link](); // allowed
}
}

Output:
age and display() have default access
Since both classes are in the same package, access is allowed.
____________________________________________________________________________________________________________
____________________________________________________________________________________________________________
ACCESSING DEFAULT IN DIFFERENT PACKAGE [ERROR]
package package1;

class Student {

int age = 20; // default


}
____________________________________________________________________________________________________________
package package2;

import [Link];

public class Main {

public static void main(String[] args) {

Student s = new Student();


[Link]([Link]); // ERROR
}
}

Explanation:
default access = same package only.

 Private
◦ A private variable, method, or constructor can only be accessed inside the same class. It can NOT be accessed from another
class, even if the class is in the same package.
class Student {

private int age = 20;

private void display() {


[Link]("Age: " + age);
}

public static void main(String[] args) {


Student s = new Student();
[Link]([Link]); // allowed
[Link](); // allowed
}
}

Explanation:
age and display() are private
They are accessible inside the same class
____________________________________________________________________________________________________________
____________________________________________________________________________________________________________
ACCESSING PRIVATE OUTSIDE THE CLASS [ERROR]
class Student {

private int age = 20;


}

public class Main {

public static void main(String[] args) {

Student s = new Student();


[Link]([Link]); // ERROR
}
}

Output:
Compilation Error: age has private access in Student.
Explanation:
private members cannot be accessed outside the class.
____________________________________________________________________________________________________________
____________________________________________________________________________________________________________
ACCESSING PRIVATE USING GETTER AND SETTER (ENCAPSULATION) -> Used in real application
class Student {

private int age;

public void setAge(int age) {


[Link] = age;
}

public int getAge() {


return age;
}
}

public class Main {

public static void main(String[] args) {

Student s = new Student();

[Link](25);
[Link]([Link]());
}
}

Output:
25

Explanation:
age is private.
Access is controlled through public methods.
____________________________________________________________________________________________________________
____________________________________________________________________________________________________________
PRIVATE CONSTRUCTOR EXAMPE (Sometimes constructors are also private) -> used in Singleton design pattern
class Test {

private Test() {
[Link]("Object created");
}

public static void main(String[] args) {

Test t = new Test(); // allowed inside same class


}
}

 Protected
◦ A protected member can be accessed in another package only through inheritance (subclass). However, you can NOT access it
using a parent class object. You must access it through the subclass object.
package package1;

public class Parent {

protected int x = 10;

protected void display() {


[Link]("Protected method");
}
}
____________________________________________________________________________________________________________
package package2;

import [Link];
public class Child extends Parent {

public static void main(String[] args) {

Child c = new Child();

[Link](c.x); // allowed
[Link](); // allowed
}
}
____________________________________________________________________________________________________________
package package2;

import [Link];

public class Child extends Parent {

public static void main(String[] args) {

Parent p = new Parent();

[Link](p.x); // ❌ Compilation Error


}
}

 Public
◦ public is the least restrictive access modifier in Java.
◦ A public class, variable, method, or constructor can be accessed from anywhere:
▪ Same class
▪ Same package
▪ Subclass
▪ Different package
class Student {

public int age = 20;

public void display() {


[Link]("Age: " + age);
}
}

public class Main {

public static void main(String[] args) {

Student s = new Student();

[Link]([Link]); // allowed
[Link](); // allowed
}
}

Output:
Age: 20

Explanation:
age and display() are public
They can be accessed from any class
____________________________________________________________________________________________________________
____________________________________________________________________________________________________________
PUBLIC CLASS CAN BE USED FROM ANY PACKAGE
package pakage1;

public class Test {

public void show() {


[Link]("Hello Java");
}
}
____________________________________________________________________________________________________________
package package2;

import [Link];

public class Main {

public static void main(String[] args) {

Test t = new Test();


[Link]();
}
}

Explanation:
Access works because the class and method are public.
____________________________________________________________________________________________________________
____________________________________________________________________________________________________________
PUBLIC CONSTRUCTOR
class Car {

public Car() {
[Link]("Car object created");
}
}

public class Main {

public static void main(String[] args) {

Car c = new Car();


}
}

Output:
Car object created.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Methods
 Block of code grouped together to perform a certain task or operation.
 Achieve re-usability.
 Write once, use many times.
 Easy modification and readability.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Constructor
 Special Type of method, Called when instance of the class is created and memory of object is allocated.
 Java Compiler provides default constructor, if there is no constructor available.
 Used to assign values to the class variables at the time of object creation, either explicitly done by the programmer or by Java itself
(default constructor).
 Name Same as class.
 No Return Type.
void Test() { } // This becomes a method, not constructor
 Can NOT be abstract, Static, Final and Synchronized.
class Student {

int age;

Student() {
age = 20;
}

public static void main(String[] args) {


Student s = new Student();
[Link]([Link]);
}
}

Output:
20

Explanation:
Memory for the object is allocated in heap.
The constructor is automatically called.
Variables are initialized
 Java provides a Constructor class which can be used to get the internal information of a constructor in the class. It is found in the
[Link] package.
 Constructor chaining is the process of calling one constructor from another constructor with respect to current object. Within same
class: It can be done using this() keyword. From base class: by using super() keyword.
 Destructor: There is no concept of destructor in Java. In place of the destructor, Java provides the garbage collector that works the
same as the destructor. It automatically deletes the unused objects (objects that are no longer used) and free-up the memory. The
programmer has no need to manage memory manually. It can be error-prone, vulnerable, and may lead to a memory leak.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Java Source File Structure
 Java program can contain any number of classes.
 A Java source file may have any name, but if it contains a public class, then the source file name must be exactly the same as the
public class name.

// File name: [Link]


class A {

}
class B {

}
class C {

// File name: [Link]


public class P01ClassNaming {

}
class A {

}
class B {

}
class C {

 A Java source file can contain at most one public class. If more than one public class is declared in the same source file, the compiler
throws an error.
// File name: [Link]
public class P01ClassNaming {

}
public class A {

}
class B {

}
class C {

}
Output: java: class A is public, should be declared in a file named [Link]

 The Java file name is decided ONLY by the public class. The class containing main() can be public or non-public. If no public class
exists, the file can be named anything.

// File name: [Link]


class Test {
public static void main(String[] args) {
[Link]("Hello");
}
}
javac [Link] -> compile
java Test -> run

// File name: [Link]


public class PublicClass {
}

class Runner {
public static void main(String[] args) {
[Link]("Running");
}
}
javac [Link]
java Runner

// File name: [Link]


public class App {
public static void main(String[] args) {
[Link]("Start");
}
}
javac [Link]
java App

// File name: [Link]


class A {
public static void main(String[] args) {
[Link]("A class main");
}
}
class B {
public static void main(String[] args) {
[Link]("B class main");
}
}
class C {
public static void main(String[] args) {
[Link]("C class main");
}
}
class D {

}
We can use any name for the file.

◦ After compilation javac [Link] -> Generated files: [Link], [Link], [Link], [Link]
◦ Each class generates a separate .class file, and the JVM executes the main() method of the class specified in the java command.
In above program, 4 classes will get generated.
▪ When I execute java A -> JVM finds main() in class A
▪ java B -> JVM finds main() in class B
▪ java C -> JVM finds main() in class C
▪ java D -> Class D does not contain main() -> JVM throws runtime error -> Error: Main method not found in class D
▪ java P01ClassNaming -> Runtime error will be thrown -> Error: Could not find or load main class P01ClassNaming
Caused by: [Link]: P01ClassNaming

import statement

package OopsConcept;

public class P02ImportStatement {


public static void main(String[] args) {
ArrayList list = new ArrayList();
}
}

/*
OUTPUT
java: cannot find symbol
symbol: class ArrayList
location: class OopsConcept.P02ImportStatement
*/
Solution: import ArrayList Class (import [Link]),
else use fully qualified name: [Link] list = new [Link]();

 In Java, imports are of two types


◦ Implicit import (Automatic Import)
▪ Packages that are automatically available to every Java program without writing an import statement are called implicit
imports.
▪ Implicity imported packages: [Link].* -> this package is always imported by JVM.
▪ Common Classes from [Link]
 String
 System
 Object
 Math
 Thread
 Exception
 StringBuffer
class Test {
public static void main(String[] args) {
String s = "Hello";
[Link](s);
}
}
// No import needed; String and System come from [Link]

◦ Explicit import (recommended)


▪ When a class or package is manually imported using the import keyword, it is called explicit import.
▪ import [Link];
import packageName.*;
▪ Explicit Class import -> imports only one specific class
import [Link];

class Test {
public static void main(String[] args) {
Scanner sc = new Scanner([Link]);
}
}
Recommended; No ambiguity; Faster readability
▪ Explicit Pakage import -> imports all classes of a package (not sub-packages)
import [Link].*;

class Test {
ArrayList list = new ArrayList();
}

▪ Why * does NOT import sub-packages?


 In Java, sub-packages are NOT imported automatically. Each sub-package must be imported explicitly using its own
import statement.
 import [Link].*; -> imports classes inside [Link]
does NOT import
◦ [Link]
◦ [Link]
◦ [Link]
Each sub-packages is treated as a completely separate package.
▪ Import a specific class from sub-package
import [Link];
▪ Import all classes from sub-package
import [Link].*;
▪ Import multiple sub-packages separately
import [Link].*;
import [Link].*;
import [Link].*;

 All compiled classes (.class files) available in the current working directory are automatically available to a Java program, without
using an import statement.
◦ The current working directory (.) is part of the default classpath. JVM and compiler search the classpath to locate classes.
Hence, casses in the same directory (default package) are found automatically. (Java works with compiled bytecode, not source
files.)

src
├── Arrays
├── Concurrency_and_Multithreading
├── OopsConcept
│ ├── [Link]
│ ├── [Link]
│ └── [Link]
├── Pattern_Printing
│ ├── [Link]
│ ├── [Link]
│ └── [Link]
└── [Link] -> move [Link] into a package, then only you can access

src
└── Generics
└── [Link]
package OopsConcept;

import Pattern_Printing.Bridge; // 'Bridge' available in 'Pattern_Printing'

public class P03ImportClasses {


public static void main(String[] args) {
P02ImportStatement obj1 = new P02ImportStatement(); // NO import required; works because both are in
'OopsConcept'
}
}

 import [Link];
import java.*; // ❌ INVALID – Pattern is available inside ‘regex’ package

public class ImportPattern {


public static void main(String[] args) {
Pattern pattern = [Link]('ab');
}
}


 s
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
OOPs (Object-Oriented Programming System)

 OOPS is a programming paradigm that models real-world entities using objects and classes.
 OOPS organizes code around objects rather than functions and uses Encapsulation, Abstraction, Inheritance, and Polymorphism to
create secure and reusable software systems.
 Its primary goal is to bind data and the functions that operate on that data together, restricting direct access from outside the class.
 Core components of OOPS: class, object, encapsulation, abstraction, inheritance, and polymorphism.
 4 Pillars of OOPS:
 Encapsulation
 Wrapping data and methods into a single unit and restricting direct access.
 Achieved by:
 Making variables private.
 Providing getter and setter methods.

 Benefits:
 Data hiding
 Controlled access
 Security
 Abstraction
 Showing only essential details and hiding implementation.
 Achieved by:
 Abstract classes
 Interfaces
 Eg., When you drive a car, you use steering and pedals - you do NOT see engine complexity.
 Inheritance
 One class acquires properties and methods of another class.

 Benefits:
 Code re-usability
 Logical hierarchy
 Polymorphism
 “Many forms” A single action behaves differently in different situations.
 Types:

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Class
 Group of objects which have common properties. It is a template or blueprint from which objects are created. It is a logical entity. It
can NOT be physical.
 Defines properties (variables) and behaviors (methods).
 Class contains fields, methods, constructors, blocks, nested class, and interface.
 Modifiers: Private < Default < Protected < Public
 Constructor
 Special method that is used to initialize objects. The constructor is called when an object of a class is created. It can be used to set
initial values for object attributes. Same name, no return type, Called only once.
 Types: Default and Parameterised contructors

 A class can have multiple constructors, a concept known as constructor overloading. Each constructor must have a unique
signature (different number and/or types of parameters) to allow the compiler to distinguish between them. A specific constructor
is invoked explicitly using the new keyword when an object is instantiated, matching the arguments provided at that time.
Constructors are used to initialize the instance variables of a newly created object.
 Blocks
 A block is a group of zero or more statements enclosed within curly braces { }.
 Types of blocks:
 Instance Block (or Non-static Block)
 A block that runs every time an object is created, before the constructor executes.

 Executes each time object is created.


 Runs before constructor.
 Can access instance variables.
 Rarely used in real-world modern code.
 Static Block
 A block that runs once when the class is loaded into memory. [static block are executed only at the time class is loaded
and before the main() method is called]
 Static variable initialization.
 Loading drivers (older JDBC).
 Complex static configuration.
 A class can have any number of static {} blocks. If there are multiple static blocks, they are executed automatically by
the JVM in the order in which they appear in the source code, when the class is first loaded into memory. This happens
only once, before any objects are created or static method are called. They are primarily used to initialize static
variables that require complex setup.
 Constructor Block (or Constructor)
 NOT technically a “block type”, but it contains a block of code.

 Runs when object is created.


 Local Block
 Any block inside a method or control structure.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Object
 Physical as well as a logical entity, that has state (represented by attributes of an object; also reflects the properties of an object. Eg.,
breed, age, color), behavior (represented by methods of an object; also reflects the response of an object with other objects,
functionalities. Eg., bark, sleep, eat) and identity (gives a unique name to an object and enables one object to interact with other objects.
Eg., name of the dog).
 Instance (an example or case of something) of a class.
 Represents real-world entity.

 Ways to create an object of a class:


 Using new keyword:
 This is the standard and most frequently used method.
ClassName obj = new ClassName();

Test t = new Test();


Explanation:
new Test() → creates object in heap memory
t → reference variable pointing to that object

 Using [Link](String className) method (Reflection):


 This method loads a class dynamically at runtime.
class Test {
void display() {
[Link]("Object created using reflection");
}
}

public class Main {


public static void main(String[] args) throws Exception {

Test obj = (Test) [Link]("Test").newInstance();


[Link]();
}
}
Explanation:
[Link]("Test") → loads the class
.newInstance() → creates object
 Used in JDBC drivers, and frameworks (Spring, Hibernate).
 Note: newInstance() is deprecated in modern Java, replaced with:
Test obj = [Link]().newInstance();

 Using clone() method:


 Creates a copy of an existing object.
 The class must implement Cloneable interface.
class Test implements Cloneable {

int x = 10;

public Object clone() throws CloneNotSupportedException {


return [Link]();
}
}

public class Main {


public static void main(String[] args) throws Exception {

Test t1 = new Test();


Test t2 = (Test) [Link]();

[Link](t1.x);
[Link](t2.x);
}
}

 Using Deserialization:
 Used when reading an object from a file.
import [Link].*;

class Test implements Serializable {


int a = 10;
}

public class Main {


public static void main(String[] args) throws Exception {

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


ObjectInputStream in = new ObjectInputStream(file);

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

[Link](obj.a);
}
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Inheritance
 Inheritance is an Object-Oriented Programming (OOP) concept where one class acquires the properties and behaviors (fields and
methods) of another class.
 It helps in code reuse and establishing relationships between classes.

Animal → Parent class (or Base class or Superclass)


Dog → Child class (or Derived class or Subclass)
Dog inherits properties of Animal.

class Parent {
// properties and methods
}

class Child extends Parent {


// inherits Parent
}

class Animal {

void eat() {
[Link]("Animal is eating");
}
}

class Dog extends Animal {

void bark() {
[Link]("Dog is barking");
}

public static void main(String[] args) {

Dog d = new Dog();

[Link](); // inherited method


[Link](); // own method
}
}

Output:
Animal is eating
Dog is barking

Explanation:
Dog inherits eat() from Animal
Dog also has its own method bark()

Types of Inheritance
 Single Inheritance
 One child class inherits from one parent class.
A→B

class A {
void show() {
[Link]("Class A");
}
}

class B extends A {
void display() {
[Link]("Class B");
}
}
____________________________________________________________________________________________________________________
____________________________________________________________________________________________________________________
class Vehicle {
String name;
int NoOfWheels;

void start() {
[Link](name+" has started.");
}
}
class Car extends Vehicle {
void accelerate() {
[Link]("Car has been accelerated.");
}
static void main() {
Car car = new Car();
[Link] = "Ferrari";
[Link] = 4;
[Link]();
[Link]();
}
}

 Multilevel Inheritance
 Inheritance chain of multiple levels.
A→B→C
class A {
void show() {
[Link]("Class A");
}
}

class B extends A {
void display() {
[Link]("Class B");
}
}

class C extends B {
void print() {
[Link]("Class C");
}
}

 Hierarchical Inheritance
 Multiple child classes inherit from one parent class.
A
/ \
B C

class A {
void show() {
[Link]("Class A");
}
}

class B extends A { }

class C extends A { }


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Encapsulation
 Encapsulation is the process of wrapping data (variables) and code (methods) together into a single unit.
 In Java, this unit is a class.

 How Encapsulation is achieved in Java?


 A class becomes fully encapsulated when:
 All variables are private.
 Access is provided through Getter and Setter methods.
class Employee {

private int id; // private data

public int getId() { // getter


return id;
}

public void setId(int id) { // setter


[Link] = id;
}
}

Explanation:
id can NOT be accessed directly
It can only be accessed through methods

 Why Encapsulation is important?


 Data Hiding
 Direct access to variables is restricted.

 Control over data


 You can apply validation rules inside setters.

 Better security
 External classes can NOT directly modify the data. Only controlled methods can change it.
 Better maintainability
 If you change internal logic, other code does NOT break.
 Eg., You modify salary calculation internally but the interface (getter/setter) remains the same.
 Helps in unit testing
 Encapsulation allows controlled testing of methods and data.
 Real life analogy: Think about an ATM machine. You interact only with withdraw, deposit, check balance. But the internal banking system
is hidden. This is Encapsulation.
 User → ATM Interface → Bank System (Hidden)
 this keyword is used to represent the current object.

public class Employee {


private int EmpId;
private String name;
private String role;
private int salary;
private String dob;

public int getEmpId() {


return EmpId;
}

public void setEmpId(int empId) {


EmpId = empId;
}

public String getName() {


return name;
}

public void setName(String name) {


[Link] = name;
}

public String getRole() {


return role;
}

public void setRole(String role) {


[Link] = role;
}

public int getSalary() {


return salary;
}

public void setSalary(int salary) {


[Link] = salary;
}

public String getDob() {


return dob;
}

public Employee setDob(String dob) {


[Link] = dob;
return this;
}

static void main() {


Employee emp = new Employee();
[Link](01);
[Link]("Satyam");
[Link]("Senior Executive");
[Link](25000);
[Link]("12/03/2000");
[Link]([Link]()+" "+[Link]()+" "+[Link]()+" "+[Link]()+" "+[Link]());
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Abstraction
 Abstraction is the process of hiding implementation details and showing only essential functionality to the user.
 The user knows what the system does, but NOT how it does it.
 Eg., When you drive a car, you use the steering wheel, accelerator, and brakes — but you don’t need to know how the engine works
internally → That’s abstraction.
 Or When you send a message on WhatsApp, you just type and press send — you don’t see how the data is transmitted, encrypted, or
stored. All that complexity is hidden from you. That’s abstraction in action
 How Abstraction is implemented in Java?
 Abstraction can be achieved by:
 Abstract class: Using the abstract keyword; can contain both abstract and concrete methods.
 Interface: 100% (or nearly complete) abstraction; defines only method signatures (no implementation, except default or
static methods).

abstract class Animal {


// Abstract method (no body)
abstract void makeSound();

// Concrete method (has body) or Non-abstract method


void sleep() {
[Link]("Sleeping...");
}
}

// Class 'Dog' must either be declared abstract or implement abstract method 'makeSound()' in 'Animal'
class Dog extends Animal {
void makeSound() {
[Link]("Bark");
}
}

class Cat extends Animal {


void makeSound() {
[Link]("Meow");
}
}

public class AbstractionExample {


public static void main(String[] args) {
Animal dog = new Dog(); // Upcasting
[Link]();
[Link]();

Animal cat = new Cat();


[Link]();
}
}

Output:
Bark
Sleeping...
Meow

Explanation:
Animal defines what all animals do (makeSound, sleep)
Each subclass (Dog, Cat) defines how that sound is made.
The internal sound logic is hidden → Abstraction.

interface Appliance {
void turnOn(); // abstract method
void turnOff(); // abstract method
}

// Class 'Fan' must either be declared abstract or implement abstract method 'turnOn()' in 'Appliance'
// Class 'Fan' must either be declared abstract or implement abstract method 'turnOff()' in 'Appliance'
class Fan implements Appliance {
public void turnOn() {
[Link]("Fan starts spinning at medium speed");
}

public void turnOff() {


[Link]("Fan stops spinning");
}
}
// Class 'WashingMachine' must either be declared abstract or implement abstract methods 'turnOn()' and 'turnOff()' in 'Appliance'
class WashingMachine implements Appliance {
public void turnOn() {
[Link]("Washing machine starts washing clothes");
}

public void turnOff() {


[Link]("Washing machine stops and drains water");
}
}

public class AbstractionExample2 {


public static void main(String[] args) {
Appliance fan = new Fan();
[Link]();
[Link]();

Appliance washer = new WashingMachine();


[Link]();
[Link]();
}
}

Output:
Fan starts spinning at medium speed.
Fan stops spinning.
Washing machine starts washing clothes.
Washing machine stops and drains water.

Explanation:
The interface Appliance defines what every appliance can do — turnOn() and turnOff().
The classes Fan and WashingMachine implement how those actions actually happen.
In main(), we only use the interface reference (Appliance) to call methods — this hides the internal implementation → Abstraction.

Appliance fan = new Fan();


[Link](); // ✅ works
// [Link](); ❌ won't work if not in interface

Explanation:
Here,Appliance is the interface type (abstract).
Fan is the concrete implementation class.
You’re telling Java: “I don’t care which appliance it is — just give me one that can be turned on or off.”

Why this is abstraction:


◦The reference type (Appliance) hides the actual class implementation.
◦You only know the behavior contract (methods defined in the interface).
You cannot call any methods specific to Fan that are not part of the interface. (you can only call the methods that are a part of interface)

Fan fan = new Fan();
[Link](); // ✅ works
[Link](); // ✅ also works (if defined in Fan)

Explanation:
Here, both the reference type and object type are the same (Fan).
You’re explicitly depending on the concrete class.
You now know and rely on the exact implementation — which breaks abstraction.
You can access everything the Fan class provides — even those not part of the interface.
Interface reference = new ImplementingClass(); → ✅ Abstraction
ConcreteClass reference = new ConcreteClass(); → ❌ No abstraction

abstract class Payment {


abstract void pay(double amount); // abstract method

void transactionMessage() { // concrete method


[Link]("Transaction is in process...");
}
}
// Class 'UpiPayment' must either be declared abstract or implement abstract method 'pay(double)' in 'Payment'
class UpiPayment extends Payment {
void pay(double amount) {
[Link]("Paid "+amount+"using UPI");
}
}

// Class 'CreditCardPayment' must either be declared abstract or implement abstract method 'pay(double)' in 'Payment'
class CreditCardPayment extends Payment {
void pay(double amount) {
[Link]("Paid "+amount+"using Credit Card");
}
}

public class PaymentSystem {


public static void main(String[] args) {
Payment payment;
payment = new UpiPayment();
[Link]();
[Link](1500.0);

payment = new CreditCardPayment();


[Link]();
[Link](2000.0);
}
}

Output:
Transaction in process...
Paid ₹1500.0 using UPI.
Transaction in process...
Paid ₹2000.0 using Credit Card.

Explanation:
Payment defines a general structure for all payment types.
Concrete subclasses (CreditCardPayment, UpiPayment) decide how the payment is processed.
The main program only uses the Payment reference — not caring about the internal process.
This is real-world abstraction — the user knows only what to do (pay()), not how it’s done internally.

abstract class Bank {


abstract int getInterestRate();
}

class SBI extends Bank {


int getInterestRate() {
return 7;
}
}

class HDFC extends Bank {


int getInterestRate() {
return 8;
}
}

public class Test {


public static void main(String[] args) {

Bank b;
b = new SBI();
[Link]([Link]());

b = new HDFC();
[Link]([Link]());
}
}

Output:
7
8

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Abstract Class
 A class that cannot be instantiated (you can’t create an object of it directly). It is declared using the abstract keyword.
abstract class Animal {
abstract void makeSound(); // abstract method (no body)

void eat() { // concrete (normal) method


[Link]("This animal eats food.");
}
}

Animal a = new Animal(); // ❌ Error

 An abstract class can have both the regular (or concrete) and abstract methods. A method that doesn’t have its body is known as
abstract method.
◦ Abstract methods → must be implemented by the subclass (unless the subclass is also abstract).
◦ Concrete methods → are already implemented in the abstract class, and subclasses can either use them directly or override
them if needed.

 Though abstract classes cannot be instantiated, we can create subclasses from it. We can then access members of the abstract class
using the object of the subclass.
 If the abstract class includes any abstract method, then all the child classes inherited from the abstract superclass must provide the
implementation of the abstract method.

public class LearnAbstract {


public static void main(String[] args) {
// If i try to create an object for abstract class, it would not be possible
// Vehicle veh = new Vehicle(); // 'Vehicle' is abstract; cannot be instantiated

Car c1 = new Car();


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

abstract class Vehicle {


abstract void accelerator();

// abstract void brakes(int wheels){} // Abstract method — no body


abstract void brakes(int wheels);

// Concrete method — already implemented


void honks() {
[Link]("Vehicle honks");
}
}

// Class 'Car' created in order to override abstract methods. '@Override' to check methods, if the Override method(s) exists in parent class or
not.
// Class 'Car' must either be declared abstract or implement abstract methods 'accelerator' and 'brakes(int)' in 'Vehicle'
class Car extends Vehicle {
// Must implement abstract method
@Override
void accelerator() {
[Link]("Car is accelerating");
}
@Override
void brakes(int wheels) {
[Link]("Car "+wheels+" wheels brakes are pushed");
}
void honks() {
[Link]("Car is honking");
}
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Interface
 An interface is a fully abstract class. It includes a group of abstract methods (methods without a body). We use the interface
keyword to create an interface in Java.
 To use an interface, other classes must implement it. We use the implements keyword to implement an interface.
interface Animal {
// public void abstract sound(); // modifier ‘abstract’ is redundant for interface methods; and modifier ‘public’ is also redundant
(not necessary) for interface members
void sound(); // abstract method (no body)
}

class Dog implements Animal {


public void sound() {
[Link]("Bark");
}
}
 You cannot instantiate (create objects of) an interface, just like you can NOT instantiate an abstract class, because both are
incomplete blueprints — they only define what should be done, not how it’s done.
// Animal a = new Animal(); ❌ Not allowed
Animal a = new Dog(); ✅ // Allowed (abstraction)
 There can be only abstract methods in Java interface, NOT the method body. All the methods are public and abstract.
interface Vehicle {
void start(); // same as public abstract void start();
}
 All variables are public, static, and final. And all variables defined inside interface must be initialized.
interface Car {
// int MAX_SPEED; // NOT allowed. Variable ‘MAX_SPEED’ might not have been initialized
int MAX_SPEED = 180; // public static final by default
}
You can access the constant in main(), using interfaceName.CONSTANT_VALUE. You also cannot change or modify the value of
variable defined inside interface, as it will be shared by all other classes that implements an interface.
// Vehicle.MAX_SPEED = 250; ❌ Not allowed

 Multiple Inheritance means - A class can inherit features (methods/properties) from more than one parent.
◦ Java does not support multiple inheritance using classes because of the Diamond Problem.
class A {
void show() {
[Link]("show() method of class A");
}
}

class B {
void show() {
[Link]("show() method of class B");
}
}

class C extends A, B { // class can NOT extend multiple classes


// which 'show()' should be called? A or B?
}
◦ Supports Multiple inheritance → A class can implement more than one interface.
interface Printable {
void print();
}

interface Showable {
void show();
}

class Report implements Printable, Showable {


public void print() {
[Link]("Printing...");
}

public void show() {


[Link]("Showing...");
}
}
 Abstraction = Hiding the implementation details and showing only the essential features.
◦ How Interface provides abstraction?
▪ An interface contains only method declarations (signatures) — not implementations.
▪ The class that implements the interface provides the implementation (how it works).
▪ When you use the interface reference, you cannot see or access the internal implementation — you only know what
actions are available.
▪ This separation of what vs how is the essence of abstraction.
interface Vehicle {
void start(); // abstract method (no implementation)
}

class Car implements Vehicle {


public void start() {
[Link]("Car starts with a key.");
}
}

class Bike implements Vehicle {


public void start() {
[Link]("Bike starts with a button.");
}
}

public class TestAbstraction {


public static void main(String[] args) {
Vehicle v = new Car(); // interface reference
[Link](); // abstraction in action
}
}

Output:
Car starts with a key.
 Interfaces can have default methods with implementation (Java 8+)
interface SmartDevice {
void turnOn();

default void connectWiFi() {


[Link]("Connecting to WiFi...");
}
}

class SmartTV implements SmartDevice {


public void turnOn() {
[Link]("Smart TV is ON");
}
}

Output:
Smart TV is ON
Connecting to WiFi...
◦ Before Java 8, interfaces were very restrictive. We could only define abstract methods and public static final variables
(constants). And Interfaces could NOT contain method implementations. Every method was implicitly abstract. Implementing
classes must override all methods.

◦ Solution introduced in Java 8 as Default methods. A default method allows an interface to provide a method implementation.

 Static methods belong to the interface itself, NOT to objects (Java 8+).
interface Gadget {
static void info() {
[Link]("Gadgets are electronic devices.");
}
}

[Link](); // ✅ Called directly

 When a class wants to extend something from another class, we use extends keyword. When a class wants to inherit
something from interface, we use implements keyword. When a interface wants to inherit something from another
interface, we use extends keyword.
 There is a parent class, and interface wants to inherit from that. Is it possible? No, this is NOT possible in Java. An
interface cannot inherit from a class. Interfaces can only extend other interfaces. In Java, a class and an interface have
different purposes: Class → contains state (variables) + behavior (methods with implementation). Interface → defines
contracts (method declarations). Because of this design, an interface cannot inherit implementation from a class.

 An interface which has no member is known as a marker/tagged interface. Eg., Serializable, Cloneable, Remote, etc. They
are used to provide some essential information to the JVM, so that JVM may perform some useful operation.

Cloneable Interface
 In Java, the Cloneable interface is a marker interface present in the Java [Link] package.
 A marker interface means it does NOT contain any methods, but it signals the JVM that a class allows cloning of its
objects.
 Cloning means creating an exact copy of an existing object in memory.
 If a class does NOT implement Cloneable and we try to clone it using clone(), Java throws: CloneNotSupportedException.
 Java's [Link] method creates a copy of an object, but it only works when the class implements Cloneable. Without
Cloneable : Exception in thread "main" [Link]. So, Cloneable tells JVM: “This class allows
object cloning”.
 To clone an object in Java: Implement Cloneable interface, override clone() method, call [Link](), and handle
CloneNotSupportedException.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Polymorphism
 Polymorphism means “many forms.”
 In OOPs, one task can be performed in different ways using the same interface or method name.
 Example idea: A person can be a father, employee, or husband depending on the situation.
 Polymorphism helps to:
 Write flexible code.
 Improve code readability.
 Support method reuse.
 Enable dynamic behavior in programs.
 There are two types of Polymorphism:
 Compile-Time Polymorphism (Static binding)
 The method to execute is decided during compilation.
 Achieved through Method Overloading (same method name but different parameters).
class MathUtil {
int add(int a, int b) {
return a + b;
}

int add(int a, int b, int c) {


return a + b + c;
}

double add(double a, double b) {


return a + b;
}
}

Explanation:
Here add() behaves differently depending on parameters

 Run-Time Polymorphism (Dynamic binding)


 The method to execute is decided during runtime.
 Achieved through Method Overriding (a child class provides its own implementation of a method defined in the parent class).
class Animal {
void sound() {
[Link]("Animal makes sound");
}
}

class Dog extends Animal {


void sound() {
[Link]("Dog barks");
}
}

class Test {
public static void main(String[] args) {
Animal a = new Dog();
[Link]();

}
}

Output:
Dog barks

Explanation:
Here the method is decided at runtime.

 Method Overloading
 When there are multiple functions with the same name but different parameters then these functions are said to be overloaded.
 Increases readability.
 Functions can be overloaded by change in the number of arguments or/and change in the tye of arguments. Can NOT overload by
return type. Type Conversion but to higher type, if exact prototype does NOT match. We can overload static methods. We can
overload main method too.

 If no method exactly matches the argument type, Java will automatically promote the argument to the next higher compatible
data type to find a matching [Link] happens during compile-time polymorphism (method overloading resolution).
 Primitive promotion order in Java: byte → short → int → long → float → double
 Java will move upward in this hierarchy to find the closest matching method. [int can NOT accept double values.]

 Method Overriding
 Overriding is a feature that allows a subclass or child class to provide a specific implementation of a method that is already
provided by one of its super-classes or parent classes.
 When a method in a subclass has the same name, same parameters or signature, and same return type (or sub-type) as a
method in its super-class. Also called Dynamic Method Dispatch. [case of Method Overriding]
 Function call to the overriden method is resolved at runtime.
 It is the type of the object being referred to (not the type of the reference variable) that determines which version of a overriden
method will be executed.
 We can NOT override static methods, its data hiding.

 If we comment out the child body, then it will print the Parent class value.

 If we try to upcast the reference type:

 Parent Reference (parentChildObj) is referring to child object, and this scenario is known as Dynamic Method Dispatch. And
in such case, which method to call is decided at runtime, based on which object is referred to. So, the parent reference is
referring to the child object, so at the runtime it decides that I am referrring to child object, so I am going to call the method
which is present in child class. But for the case of variable, it looks for the variable on the basis of reference it has. If the
reference is of parent class, it is going to read first that variable from parent class, or may be I can say from the class of which
reference is being used for. This phenomena is also known as Upcasting. When a reference of a parent class is referring to the
object of a child class.
[When a parent class reference refers to a child class object, it is called Upcasting. In this situation, overridden methods
follow Dynamic Method Dispatch, meaning the method is resolved at runtime based on the object type, whereas variables
are accessed based on the reference type.]

 Child can NOT refer to the Parent. This is NOT allowed.


 When a child class overrides a method of the parent class, normally only the child method executes. If you want to execute both
the parent method and the child method, the child class must explicitly call the parent method using the super keyword. super
refers to the immediate parent class object.
 super.method1() calls the parent class method. Then the child class method continues execution. So both methods run.
 When super keyword is used?

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Static
 The static keyword in Java is used for class-level members.
 It means the member belongs to the class rather than to individual objects.
 Static members are shared by all objects.
 They are loaded into memory once when the class is loaded.
 Static variable (class variable)
 A static variable is shared among all objects of the class.
 Only one copy exists in memory.
 Stored in the class area (method area).
 Created when the class is loaded.
 All objects share the same value.
 [Link] does NOT work in some contexts because this refers to the current object (instance) of the class, while a static
variable belongs to the class, not to an object.

 How can I load the collegeName before the main() method gets executed? Using static block.

 Static class
 Class can be made static only if it is nested class. We can NOT declare a top-level classes with a static modifier, but can declare
nested class as static. Nested class does NOT need a reference of Outer class.
 In this case, a static class can NOT access non-static members of the of the Outer class.

 Static method
 A static method belongs to the class, NOT to objects.
 Can be called without creating an object.
 Can access only static variables and static methods directly.
 Can NOT directly access non-static members.
 Static block
 A static block is used to initialize static variables.
 Executes only once.
 Runs when the class is loaded.
 Executes before the main method.

 The static keyword in Java is used to create class-level variables, methods, blocks, or nested classes that belong to the class rather than
to objects and are shared across all instances.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Inner classes and Nested Static class


 An inner class is a class that is declared inside another class. It is used to logically group classes that are only used in one place, and it
helps increase encapsulation and readability.
 Types of Inner classes:
 Non-static Inner Class (Regular Inner Class)
 A non-static inner class is a class declared inside another class without the static keyword.
 It is associated with an instance of the outer class, meaning:
 You can NOT create an object of the inner class without creating an object of the outer class first.
 The inner class can access all members (including private ones) of the outer class.
// Syntax
class Outer {
class Inner {
// body of inner class
}
}

// To create an object:
Outer outer = new Outer();
[Link] inner = [Link] Inner();

 Example: Regular (Non-static) Inner Class


class Car {
class Outer {
private String message = "Hello from Outer class";

class Inner {
void display() {
// Can access private members of Outer
[Link](message);
}
}
}

public class Test {


public static void main(String[] args) {
Outer outer = new Outer(); // Step 1: Create Outer object
[Link] inner = [Link] Inner(); // Step 2: Create Inner object
[Link](); // Step 3: Call inner method
}
}

Output:
Hello from Outer class

 Example with Outer and Inner methods


class Car {
private String model = "Tesla Model 3";

class Engine {
void start() {
[Link](model + " engine started!");
}
}

void run() {
Engine e = new Engine();
[Link]();
}
}

public class Main {


public static void main(String[] args) {
Car car = new Car();
[Link](); // or create inner class object separately
}
}

Output:
Tesla Model 3 engine started!

 s

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Final
 The final keyword in Java is used to restrict changes. [Used to restrict the user.]
 It can applied to variables, methods, and classes.
 Final variable
 A final variable can NOT be modified once it is assigned a value. It behaves like a constant.

 A blank final variable is declared without initialization but must be initialized once. [If we are creating a blank final variable, you
will be allowed to assign the value to that variable at least once, or at most once. In simple words, you can only assign the value for
a single time.]

 It can be initialized in a constructor or in a static block.

 If the final variable is a reference, this means that the variable can NOT be re-bound to reference another object.

 Represent final variables in all uppercase, using underscore to separate words.


 In Java, by coding convention (not a compiler rule), final variables that act as constants are written in UPPERCASE with
underscores between words. This improves readability, and immediately signals that the value shoul NOT change.

 The uppercase rule applies mainly to static final constants, because they represent global constants for the class.

 Final method
 A final method can NOT be overridden by a subclass.
 Prevent modification of critical behavior.

 Final class
 A final class can NOT be inherited.
 Eg., all Wrapper classes like Integer, String, Float, Double. To create an immutable class like the predefined String class. One can
NOT make a class immutable without making it final.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Factory Design Pattern
 The Factory Design Pattern is a creational design pattern used in Object-Oriented Programming and widely used in Java.
 Its main idea is: Move the object creation logic from the client code to a separate factory class.
 Instead of the client directly creating objects using new, it asks a factory class to create the object.
 This improves loose coupling (change at one place, does NOT affect the other part), code flexibility, and maintainability.

 Interface (Shape)
 The top layer contains an interface called Shape.
 It defines a contract.
 Any shape must implement the draw() method.
 Concrete Classes
 Three classes implement the interfaces: Circle, Square, Rectangle.
 They provide their own implementation of draw().
 All these classes implement the same interface but behave differently.
 Factory Class (ShapeFactory)
 The factory class is responsible for object creation.
 The factory decides which object to create.
 The client does NOT know the actual class being instantiated.
 Client Code (FactoryDesignPattern)
 The client asks the factory for objects.
 Flow of execution
 Client calls ShapeFactory.
 Client requests an object (getShape()).
 Factory decides which class to instantiate.
 Factory returns the object.
 Client uses the object through the Shape interface.
interface Shape {
void draw();
}
class Circle implements Shape {
public void draw() {
[Link]("Drawing Circle");
}
}
class Square implements Shape {
public void draw() {
[Link]("Drawing Square");
}
}
class Rectangle implements Shape {
public void draw() {
[Link]("Drawing Rectangle");
}
}

class ShapeFactory {
public Shape getShape(String shapeType) {
if(shapeType == null) return null;
if([Link]("CIRCLE"))
return new Circle();
if([Link]("SQUARE"))
return new Square();
if([Link]("RECTANGLE"))
return new Rectangle();
return null;
}
}

public class FactoryDesignPattern {


static void main() {
ShapeFactory factory = new ShapeFactory();

Shape shape1 = [Link]("CIRCLE");


[Link]();

Shape shape2 = [Link]("SQUARE");


[Link]();

Shape shape3 = [Link]("RECTANGLE");


[Link]();
}
}

 The Factory Method Pattern is a creational design pattern that provides an interface for creating objects, but lets subclasses decide
which class to instantiate.
 In simple terms: Instead of creating objects using new, the factory method creates the object for you.
 Why it is needed?

 Factory Method solution:


 Why it is called Virtual Constructor?
 Because the factory method behaves like a constructor, but the actual object type is decided at runtime.
 Advantages:
 Loose coupling.
 Encapsulation of object creation.
 Easier code maintenance.
 Client does NOT depend on concrete classes.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Design Patterns
 Design Patterns are reusable solutions to common software design problems that occur during application development.
 They are NOT ready-made code, but templates or blueprints that help developers design flexible and maintainable systems using
Object-Oriented Programming principles.
 In simple terms: A Design Pattern is a standard way to solve a commonly occurring problem in software design.
 Problems that mainly occur:
 Creating objects efficiently.
 Structuring classes properly.
 Managing communication between objects.
 Why Design Patterns are important?
 Reusable solutions
 Design patterns provide general solutions to recurring problems in software design.
 Instead of reinventing the solution every time, developers can apply an already proven approach.
 Eg., Instead of writing complex object creation logic repeatedly, developers can use the Singleton Pattern.
 Established best practices
 Design patterns are considered best practices discovered by experienced developers over many years.
 They were popularized by the famous book: “Design Patterns: Elements of Reusable Object-Oriented Software”. The authors
are often called the Gang of Four (GoF).
 Improved Communication
 Design patterns provide a common vocabularly for developers.
 Eg., Instead of explaining a long design structure, a developer can say: “We should use the Factory Pattern here”.
Immediately everyone understands the approach.
 Better maintainability and scalability
 Design pattern promote loose coupling, high cohension, and better modular structure. This leads to easier maintenance,
easier testing, and better scalability.
 Design patterns are broadly divided into three categories:
 Creational Patterns
 Structural Patterns
 Behavioral Patterns

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 s
Exception Handling

Exception
 An unexpected event that occurs during program execution. It affects the flow of the program instructions which can cause the
program to terminate abnormally.
 An exception can occur for many reasons. Some of them are:
◦ Invalid user input ([Link])
◦ Device failure ([Link])
◦ Loss of network connection ([Link], [Link], [Link])
◦ Physical limitations (out of disk memory or out of RAM) ([Link] → Heap space exhausted (RAM),
[Link]: No space left on device → Disk storage is full)
◦ Code errors ([Link], [Link], [Link])
◦ Opening an unavailable file ([Link])
 Types of Exception:
◦ Runtime Exceptions (Unchecked Exceptions)
▪ java Main -> run-time
▪ These are programming errors that happen during execution (runtime) – not checked at compile-time.
▪ They are the subclasses of [Link].
▪ If it is runtime exception, its your fault.
▪ Compiler does not force you to handle them (no need for try-catch or throws)
▪ Examples:

▪ Why they occur?


 logic mistakes
 invalid assumptions by the programmers
 unexpected input that code didn’t check for

◦ IOExceptions (Checked Exceptions)


▪ javac [Link] -> compile step
▪ These are input/output-related exceptions that occur when your program interacts with external resources like files,
network, or devices.
▪ They are subclasses of [Link] and must be handled using try-catch or declared with throws.
▪ Compiler forces you to handle them – otherwise the code won’t compile.
▪ Recovery usually possible.
▪ Examples:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Exception Handling

 Defining alternative way to continue rest of the program normally.

[Link]
└── [Link]
├── [Link]
│ ├── Checked Exceptions
│ └── Unchecked Exceptions (RuntimeException)
└── [Link]

Runtime Stack Mechanism (or Exception Propagation Mechanism)

 When a Java program runs, the JVM creates a runtime stack (also called the call stack) to store method call information. Each time a
method is called:
◦ A new stack frame is created for that method.
◦ The frame holds local variables, return address, and intermediate results.
◦ When the method finishes, its frame is popped (removed) from the stack.
◦ After completing execution, JVM destroys the empty stack after completing all methods call and terminates the program
normally.
public class Test {
public static void main(String[] args) {
doStuff();
}

public static void doStuff() {


doMoreStuff();
}

public static void doMoreStuff() {


[Link]("Hello");
}
}
// Total no. of Threads=1 (main thread)
 For every thread, the Java Virtual Machine (JVM) allocates a separate runtime stack to manage method invocations. The main()
method is invoked by the main thread, which serves as the program’s entry point. When main() calls doStuff(), a new stack frame is
created and pushed onto the thread’s runtime stack. Subsequently, doStuff() invokes doMoreStuff(), resulting in another stack frame
being pushed.
 Within doMoreStuff(), the statement [Link]("Hello") executes. After the execution completes, the doMoreStuff() stack
frame is popped (removed) from the stack. Control then returns to doStuff(), which, upon completion, also has its frame popped.
Finally, once main() finishes execution and its frame is removed, the runtime stack of the main thread becomes empty.

Default Exception Handling

class Test {
public static void main(String[] args) {
doStuff();
}

public static void doStuff() {


doMoreStuff();
}

public static void doMoreStuff() {


[Link](10 / 0);
}
}
 For every thread, the JVM allocates a dedicated runtime stack to maintain the sequence of method invocations. The main() method
is invoked by the main thread, which acts as the program’s entry point.
 When main() calls doStuff(), a new stack frame is created and pushed onto the main thread’s runtime stack. Subsequently, doStuff()
invokes doMoreStuff(), leading to the creation and pushing of another stack frame.
 Inside doMoreStuff(), the statement [Link](10/0); attempts to perform an illegal arithmetic operation (division by zero).
Instead of executing the statement, the JVM automatically creates an exception object of type [Link] with
the description “/ by zero”.
 Each method in the call stack is then examined in reverse order (from top to bottom) to determine if any of them contain
appropriate exception handling code (try-catch block) for this exception type.
 Since doMoreStuff() does not handle the exception, the JVM terminates it abnormally and removes its stack frame. Control returns
to doStuff(), which also lacks handling code, so it too terminates abnormally, and its frame is removed from the stack. Finally, the
main() method is checked; if it also does not handle the exception, the JVM’s Default Exception Handler takes over.
 The Default Exception Handler prints the exception details and stack trace to the console and terminates the program abnormally.
The output is typically as follows:

This stack trace represents the sequence of method calls that led to the exception — from where it occurred (doMoreStuff) up to where it was
initiated (main).

class Test {
public static void main(String[] args) {
doStuff();
}

public static void doStuff() {


doMoreStuff();
[Link](10 / 0);
}

public static void doMoreStuff() {


[Link]("Hello");
}
}
JVM starts execution by calling the main() method through the main thread.
→ A stack frame is created for main() inside the main thread’s runtime stack.
Inside main(), the statement doStuff(); is executed.
→ A new stack frame for doStuff() is created and pushed onto the same runtime stack.
Inside doStuff(), the statement doMoreStuff(); executes.
→ A new stack frame for doMoreStuff() is created and pushed.
Inside doMoreStuff(), [Link]("Hello"); executes successfully.
→ “Hello” is printed to the console.
→ Once completed, doMoreStuff()’s frame is popped (removed) from the stack.
Control returns to doStuff().
→ Next statement is [Link](10 / 0);.
→ Here, an ArithmeticException (/ by zero) is generated by the JVM.
Since doStuff() does not contain a try-catch block, the method terminates abnormally, and its stack frame is removed.
The JVM returns control to main() to see if it handles the exception.
→ Since main() also lacks handling code, it too terminates abnormally.
Finally, the JVM’s Default Exception Handler handles the unhandled exception and prints the stack trace:

class Test {
public static void main(String[] args) {
doStuff();
[Link](10 / 0);
}

public static void doStuff() {


doMoreStuff();
[Link]("Hi");
}
public static void doMoreStuff() {
[Link]("Hello");
}
}
1. Program Start
JVM creates a main thread.
A runtime stack is allocated for the main thread.
The JVM calls the main() method.
→ A stack frame for main() is pushed onto the runtime stack.
2. Inside main()
Executes doStuff();
→ A stack frame for doStuff() is pushed onto the stack.
3. Inside doStuff()
Executes doMoreStuff();
→ A stack frame for doMoreStuff() is pushed.
4. Inside doMoreStuff()
Executes [Link]("Hello");
→ Prints Hello
doMoreStuff() completes successfully.
→ Its frame is popped (removed) from the stack.
5. Back to doStuff()
Executes [Link]("Hi");
→ Prints Hi
doStuff() completes normally.
→ Its frame is popped from the stack.
6. Back to main()
Next statement: [Link](10 / 0);
Division by zero occurs.
→ The JVM creates an ArithmeticException object with the description “/ by zero”.
7. Exception Propagation
The exception is raised inside main().
main() does not contain any try-catch block.
Hence, main() terminates abnormally, and its frame is removed from the runtime stack.
Stack becomes empty.
8. JVM Default Exception Handler
Since no method handled the exception, the JVM’s Default Exception Handler takes over.
It prints the exception details and stack trace, then terminates the program abnormally.

 Atleast one method terminates abnormally, the total program termination is abnormal termination. If methods completed
normally, then only termination is normal termination.

Exception Hierarchy
[Link]
└── [Link]
├── [Link]
│ ├── RuntimeException
│ | ├── ArithmeticException
│ │ ├── IndexOutOfBoundsException
│ │ | ├──ArrayIndexOutOfBoundsException
│ │ | ├── StringIndexOutOfBoundsException
│ │ ├── ArrayStoreException
│ │ ├── ClassCastException
│ │ ├── IllegalArgumentException
│ │ ├── NumberFormatException
│ │ ├── IllegalStateException
│ │ ├── IndexOutOfBoundsException
│ │ │ ├──StringIndexOutOfBoundsException
│ │ ├── NullPointerException
│ │ ├── NegativeArraySizeException
│ │ ├── UnsupportedOperationException
│ │ ├── SecurityException
│ │ └── ConcurrentModificationException
│ │
│ ├── CloneNotSupportedException
│ ├── InterruptedException
│ ├── IOException
│ │ ├── EOFException
│ │ ├── FileNotFoundException
│ │ ├── SocketException
│ │ └── UnknownHostException
│ ├── SQLException
│ │ └── SQLSyntaxErrorException
│ ├── ClassNotFoundException
│ ├── InstantiationException
│ ├── NoSuchMethodException
│ ├── InvocationTargetException
│ ├── ParseException
│ ├── TimeoutException
│ ├── ExecutionException
│ ├── ReflectiveOperationException
│ └── GeneralSecurityException
│ ├── InvalidKeyException
│ ├── SignatureException
│ └── NoSuchAlgorithmException

└── [Link]
├── AssertionError
├── OutOfMemoryError
├── StackOverflowError
├── VirtualMachineError
│ ├── InternalError
│ └── UnknownError
├── LinkageError
| ├── ClassCircularityError
│ ├── ClassFormatError
│ ├── NoClassDefFoundError
│ ├── UnsatisfiedLinkError
│ └── VerifyError
└── ServiceConfigurationError

try catch block

 Used to handle exceptions and prevents the abnormal termination of the program.

 It allows your program to catch errors gracefully instead of crashing

 Basic syntax:
When an exception occurs, Java automatically creates an exception object — like ArithmeticException, IOException, etc. That object holds
information about the error message, where it occurred, and stack trace. When you catch it: catch (Exception e) , here e is that exception
object.
 getStackTrace() → It returns the stack trace elements as an array of StackTraceElement objects. Each element
represents one step (method call) in the call stack.
 getMessage() → It returns a short description or message about what went wrong. It’s usually set by Java internally
(like “/ by zero”) or by you if you throw a custom exception.
 printStackTrace() → It prints the entire call stack — showing: exception type, error message, and line numbers in the
file where it occurred.
There should be only one object - that should be globallly accessible.

[Link]
[Link]();

Creational Design Pattern

 Design patterns are well proved solution of commonly occurring problems in software design.

 Prototype Pattern
 It is used when we have to make copy/clone from existing object.
Objects are different.
Checking instance 2 times.
Handled the multi-threaded environments.
Wrapper Class

 A Wrapper Class in Java is a class that wraps (converts) a primitive data type into an object.
 Java is object-oriented, but primitive types (int, char, etc.) are not objects. Wrapper classes allow primitives to be treated as objects.
 Primitive -> Wrapper mapping
Primitive Type Wrapper Class
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

 Classes in the [Link] package (like Collection, List, Map, etc.) work only with objects, not with primitive data types. Wrapper
classes help by converting primitives into objects so they can be used with these classes.
// PRIMITIVES ARE NOT OBJECTS
int x = 10; // primitive

// [Link] COLLECTIONS STORE OBJECTS ONLY


ArrayList<int> list = new ArrayList<>(); // ❌ INVALID

// USING WRAPPER CLASSES


ArrayList<Integer> list = new ArrayList<>();
[Link](10); // int → Integer (autoboxing)

 Synchronization in multithreading requires an object (or class) lock. Hence, an object is needed to support synchronization.
◦ In Java, every object has an intrinsic lock (monitor). Synchronization works by acquiring a lock. This lock is associated with an
object (instance-level synchronization) and a class (class-level synchronization).

Autobxing & Unboxing

 The automatic conversion of primitive types to the object of their corresponding wrapper class is known as autoboxing. Eg.,
conversion of int to Integer, long to Long, double to Double, etc.
Integer obj = new Integer(12); // Constructors are Deprecated since Java 9 → Always creates a new object, which leads to
unnecessary memory usage.

Integer obj2 = new [Link](12); // uses Integer Cache. Default cache range: -128 to 127. Avoids unnecessary object creation

Integer obj3 = 12; // autoboxing

◦ valueOf() is available in all Java wrapper classes and is used to convert primitive values or strings into their corresponding
wrapper objects.
byte myByte = [Link](“10”);
float myFloat = [Link](“10.5”);
char myChar = [Link](‘A’);
Boolean myBoolean = [Link](false);

▪ Converts String → wrapper object


Integer b = [Link]("20");

 Unboxing is just the reverse process of autoboxing. Automatically converting an object of a wrapper class to its corresponding
primitive type is known as unboxing. Eg., conversion of Integer to int, Long to long, Double to double, etc.
int num = obj; // unboxing

Generics

 Generics means parameterized types. Using Generics, it is possible to create classes that work with different data types. An entity
such as class, interface, or method that operates on a parameterized tye is a generic entity.
// create a generic class
class GenericsClass<T> {
// variable of T type
private T data;

public GenericsClass(T data) {


[Link] = data;
}

// method that return T type variable


public T getData() {
return [Link];
}
}

 Example: Generic Class with One Type Parameter


public class Generics {
public static void main(String[] args) {
Student<Integer> stud1 = new Student<>(121);
Student<String> stud2 = new Student<>("warrior12");
Student<Long> stud3 = new Student<Long>(12118L);

[Link]([Link]()); // 121
[Link]([Link]()); // 12118
}
}

class Student<E> {
E id;

Student(E id) {
[Link] = id;
}

E getId() {
return id;
}
}

 Example: Generic Class with Multiple Type Parameters


public class Generics {
public static void main(String[] args) {
Student<Integer, String> stud1 = new Student<>(121, "Rajeev Shukla");
Student<String, String> stud2 = new Student<>("warrior12", "Manoj Bajpayee");
Student<Long, String> stud3 = new Student<Long, String>(12118L, "Rahul Kumar");

[Link]([Link]()); // 121
[Link]([Link]()); // Rajeev Shukla
}
}

class Student<E, V> {


E id;
V name;

Student(E id, V name) {


[Link] = id;
[Link] = name;
}

E getId() {
return id;
}

V getName() {
return name;
}
}
 The Object is the superclass of all other classes, and Object reference can refer to any object. These features lack type safety.
Generics add that type of safety feature. Generics provide strong compile-time checking. (Generics in Java are similar to templates in
C++)

 Type Safety: Generics make errors to appear compile-time than at run-time. Suppose you want to create an ArrayList that store
name of students, and if by mistake the programmer adds an integer object instead of a string, the compiler allows it. But, when we
retrieve this data from ArrayList, it causes problems at runtime.
Type Safety prevents insertion of wrong data types. And errors are detected at compile time, not runtime. This avoids ClassCastException.
// WITHOUT GENERICS
ArrayList list = new ArrayList();
[Link]("Rahul");
[Link](10); // allowed
// Problem: Runtime error when retrieving data

// WITH GENERICS
ArrayList<String> list = new ArrayList<>();
[Link]("Rahul");
[Link](10); // compile-time error

 Code Reuse: We can write a method/class/interface once and use it for any type we want.

Java Generic Method

 Similar to the generic class, we can also create a method that can be used with any type of data. Such a class is known as Generics
Method.
public <T> void genericMethod(T data) {...}

public class GenericMethod {


public static void main(String[] args) {
printData("Hello World"); // Hello World
printData(123); // 123
printData(123343L); // 123343

GenericMethod obj = new Generics();


[Link]("Extra information"); // Extra information
[Link](1532L); // 1532

static <E> void printData(E data) {


[Link](data);
}

<E> void printDoubleData(E data) { // non-static Generic method


[Link](data);
}
}

 Your generic method is unbounded


public class Generics {
public static void main(String[] args) {
printData("Hello World"); // Hello World
printData(123); // 123
printData(123343L); // 123343

Generics obj = new Generics();


[Link]("Extra information"); // Extra information
[Link](1532L); // 1532

CustomClass custom = new CustomClass();


[Link](custom); // CustomClass@<hashcode>
}

static <E> void printData(E data) {


[Link](data);
}

// <E> is an unbounded type parameter. E can be any reference type. This includes String, Integer, Long, User-defined classes
like CustomClass
<E> void printDoubleData(E data) {
[Link](data);
}
}

class CustomClass {

Bounded Generic Types

 In general, the type parameter can accept any data types (except primitve types). However, if we want to use generics for some
specific types (such as accept data of number types) only, then we use bounded types.

 In case of bound types, we use the extends keyword.

 Here, GenericClass is created with bounded type. This means GenericsClass can only work with data types that are children of
Number (Byte, Short, Integer, Long, Float, Double).
class GenericClass <T extends Number> {
public void display() {
[Link]("This is a bounded type generic class.");
}
}

 Example: Bounded Type Parameter


public class Generics {
public static void main(String[] args) {

Generics obj = new Generics();


// [Link]("Extra information"); // Not allowed
[Link](1532L); // 1532 -> Allowed

CustomClass custom = new CustomClass();


// [Link](custom); // Not allowed
}

<E extends Number> void printDoubleData(E data) {


[Link](data);
}
}

class CustomClass {

E can be only Nuber or its subclasses. <E extends Number> restricts the generic type to numeric wrapper classes, ensuring only
Number or its subclasses can be passed.

 <E extends Object> would work same as <E> means any object.
Syntax of Anonymous class

@FunctionalInterface is an optional
Only one abstract method
Objects can’t call static methods. Static methods are associated with class.
Streams

 Introduced in Java 8 (in [Link] package), that allows us to process collections (like List, Set, etc) and other data sources in a
functional and declarative way.

 The stream is a pipeline of operations: you create a stream from a source, apply zero or more intermediate operations (which produce
another stream), then apply a terminal operation to produce a result.

 A Stream is not data; it has a source (collection, array, I/O), and a chain of operations represented as a pipeline object. The work
happens when the terminal operation is invoked.

 Stream dont change the original data structure, they only provide the result as per the pipelined methods. Each intermediate operation
is lazily executed and returns a stream as a result, hence various intermediate operations can be pipelined. Terminal operations mark
the end of the stream and return the result. There should be exactly one terminal operation in the stream, without a terminal operation
the stream wouldn’t flow.

 Stream is lazy and evaluates code only when required. The elements of a stream are only visited once during the life of a stream. Like
an Iterator, a new stream must be generated to revisit the same elements of the source.
 Streams are single-pass. The pipeline processes each element once when terminal op runs. If you need to process the same source
multiple times, create a new stream each time.






Iterator also consumes elements one-by-one; streams are conceptually similar but offer many functional operations and can be
parallelized.
 Don’t store a stream for long-term reuse.
 For repeated processing, either create the stream anew or collect to a container first: List<T> copy = [Link]().collect(toList()).

 Streams are wrappers around a data source, allowing us to operate with that data source and making bulk processing convenient and
fast.
 A stream wraps the source and provides a fluent API to transform and aggregate data in bulk (i.e., operate on many elements with
concise expressions).

Stream acts like a view or pipeline connected to the original data. It doesn’t copy or modify the data. It just provides a wrapper that lets you
perform transformations on the elements inside the source.
You can chain methods together in a readable, natural way — like a sentence.
Each method returns a stream again (until the last one). This allows “fluent chaining” — no intermediate variables or nested loops. Improves
readability and reduces boilerplate code.

 map/filter/reduce allow expressing "bulk" computation (apply to every element) without explicit loops.

 Java Stream methods:
[Link](T… values) To create a stream from given values. Stream<Integer> stream = [Link](1, 2,
3);
[Link](int start, int Creates a stream of integers from start IntStream Stream = [Link](1,
end) (inclusive) to end (exclusive). 10); // 1 to 9
[Link](array) Converts an array to IntStream, int[] arr = {1, 2, 3};
LongStream, DoubleStream, or generic IntStream stream = [Link](arr);
Stream.
mapToInt() Converts objects to int values (returns Stream<String> s = [Link](“10”, “20”,
IntStream) “30”);
IntStream nums =
[Link](Integer::parseInt);
average() Returns OptionalDouble. Used only on double avg = [Link](new int[] {10,
IntStream, DoubleStream, etc. 20, 30}).average().getAsDouble(); // 20.0
max() Returns OptionalInt/OptionalDouble. int max = [Link](new int[]{5, 10,
2}).max().getAsInt(); // 10
boxed() Convert primitive stream to wrapper IntStream intStream = [Link](1,
(IntStream → Stream) 5);
Stream<Integer> boxed =
[Link]();

Example 1
int[] arr = {5, 10, 15};
double avg = [Link](arr)
.mapToInt(i -> i*2) // double every number
.average()
.getAsDouble();
int maxValue = [Link](arr)
.boxed()
.mapToInt(Integer::intValue)
.max()
.getAsInt();
[Link](avg); // 20.0
[Link](maxValue); // 15

Example 2
List<String> names = [Link]("John", "Jane", "Jack", "Dee", "Dane");
[Link]().filter(name -> [Link]('J') && [Link]()>=4)
.map(String::toUpperCase)
.sorted()
.forEach([Link]::println);

Terminal Operations

 collect: The collect method is used to return the result of the intermediate operations performed on the stream.
List numbers = [Link](2, 3, 4, 5, 3);
Set square = [Link]().map(x->x*x).collect([Link]());

 forEach: The forEach method is used to iterate through every element of the stream.
List numbers = [Link](2, 3, 4, 5, 3);
[Link]().map(x -> x * x).forEach(y->[Link](y));
 reduce: The reduce method is used to reduce the elements of a stream to a single [Link] reduce method takes a Identity (initial
value), Accumulator/Binary Operator (logic of aggregation) & combiner (in parallel mode) as a parameter.
List numbers = [Link](2, 3, 4, 5, 3);
int even = [Link]().filter(x -> x%2==0).reduce(0,(ans,i)-> ans+i);

Primitive Streams

 To work with the three most used primitive types — int, long and double — the standard library includes three primitive-
specialized implementations: IntStream (sequence of primitive int-valued elements), LOngStream , and DoubleStream.
◦ Java provides IntStream, LongStream, and DoubleStream as primitive-specialized stream types that hold primitive values (not
wrapper objects).
◦ These let you perform streaming operations (map/filter/reduce/etc.) on numbers without creating Integer/Long/Double objects
for each element.
◦ Less allocation and less GC overhead for large numeric pipelines
▪ When processing huge amounts of numeric data (like millions of integers, doubles, sensor data, logs, analytics, etc.), the
performance depends heavily on how many objects get allocated and how much work the Garbage Collector (GC) has to
do.
▪ A numeric pipeline usually means operations like: processing millions of numbers (sum, max, filter, map); data
transformations in streams; data analytics; machine-learning preprocessing; and reading numeric files or network data.
▪ Less allocation = fewer temporary objects created in memory.
▪ Less GC overhead = Garbage Collector runs less frequently and does less work.
▪ Integer, Double, Long (object wrappers) → cause:
 per-item object allocation
 pointer indirection
 GC pressure
Stream<Integer> stream = [Link]()
.map(x -> x*2)
.reduce(0, Integer::sum);
// This creates millions of Integer objects.
▪ Why ‘Less GC overhead’ matters? GC is expensive beacause it pauses the application, scans memory regions, frees objects,
and moves or compacts memory. When processing Gbs of numeric data per second, GC pauses slow down throughput
severly.
▪ How to reduce allocation & GC overhead? Use primitive arrays (int[], double[], long[]) and primitive streams (IntStream,
DoubleStream, LongStream). Avoid: Integer[], Double[], Stream<Integer>

int Integer
Type Primitive data type Wrapper (Object) class
Not in any package [Link]
Memory Stores the actual numeric value in Stores a reference to an object that
memory. contains the value.
int a = 10;S Integer b = 10;
Here, a goes on stack with value. Here, b refers to an Integer object in heap
(or Integer cache).
Default values 0 null
Null handling Cannot be null Can be null
int y = null; Integer x = null;
Usage in Collections You cannot use: Collections like ArrayList, HashMap, etc
List<int> list; // invalid require objects, not primitives:
List<Integer> list = new ArrayList<>();
Autoboxing and Unboxing Java automatically converts between int int a = 5;
and Integer: Integer b = a; // autoboxing
int a = 5;
Integer b = a; // autoboxing
int c = b; // unboxing
Peformance int is faster and memory efficient. Integer is slower because: it requires
object creation; more memory usage; and
possible null checks.
Comparison int x = 1000; Integer a = 1000;
int y = 1000; Integer b = 1000;
[Link](x == y); // true [Link](a == b); // false
[Link]([Link](b)); // true

Why?
== compares object reference.
equals() compares value.

 Boxing and unboxing does take some time, but it’s not a lots. A lot of temporary boxed objects also triggers Garbage Collection a
lot more often, and that’s a performance drain too. It all adds up, so if the stream processes a lot of integer values in a tight 'loop',
the difference can be relevant.
◦ Boxing = converting a primitive int → Integer (e.g., [Link](5) or autoboxing).
◦ Unboxing = converting Integer → int (e.g., int x = integerObj;).
◦ Boxing creates objects on the heap. In a tight numeric loop or large stream, repeatedly creating wrapper objects increases
memory churn and garbage collection overhead.
List<Integer> boxed = [Link](0, 1_000_000).boxed().collect([Link]());
// creates 1_000_000 Integer objects -> memory + GC cost

int sum = [Link](0, 1_000_000).sum(); // no boxing, much cheaper

// Large arrays, tight loops, or high-throughput streaming pipelines: prefer primitive streams to avoid many temporary wrapper
objects.

 The overhead of Integer is quite large. An int is 4 bytes for the value, while an Integer is 4 bytes for the reference plus 16 bytes for
the object, so Integer uses ~20 bytes per value, i.e. 5 times the memory.
◦ A primitive int stores the 32-bit value directly (4 bytes).
◦ An Integer is an object: you pay for the object header, the field(s), alignment/padding, and the reference you store in containers
— so memory per Integer is much larger than 4 bytes.
◦ Storing millions of numbers as Integer consumes much more memory than int[] or IntStream operations.
◦ Use primitive arrays or primitive streams when memory is a concern.



 s
Thread

 We heard about the processes, when we buy the system, we think that, if we have the multiple processors, the more the number of
processors, the system will not hang. The system will work seamlessy.

 The static code is known as program, but when that program starts execution, it becomes a process. Process is a program in
execution (means a program that is currently running in the computer and using resources like memory and CPU), and the thread is
a small task or worker inside a process that helps do work faster by doing things at the same time (basic unit of execution within a
Java program that allows multiple tasks to run concurrently within a single process).

 Eg., In mobile phone, whatsApp app installed (program) → WhatsApp opened and running (process) → One thread receives
messages, one thread send messages, and one thread downloads images (all happen at the same time i.e., thread).

 The threads help developers build responsive and efficient applications by:
◦ executing tasks in parallel
▪ Threads enable multiple tasks (such as input handling, computation, and I/O operations) to run simultaneously instead of
sequentially.
◦ effectively utilizing multi-core processors
▪ Eg., On a 4-core processor, up to 4 threads can run concurrently, maximizing CPU utilization
◦ improved application performance and responsiveness
▪ Long-running tasks can be executed in background threads, allowing the main thread to remain responsive (e.g., UI
remains smooth while data is loading).

 Process vs Thread
Process Thread
A process is an independent program in execution. Each A thread is a lightweight unit of execution that exists
process has its own address space, system resources, and within a process. Multiple threads can exist inside a single
execution context. process and execute concurrently.
Every process has its separate memory space, which include Threads within the same process share the same memory
its own heap, stack, and data segment. One process cannot space (heap and data) but have separate stacks for
directly access another process’s memory. method calls and local variables.
A process is allocated resources such as memory, files, and Threads do NOT own resources independently; they share
I/O devices independently by the operating system. the resources allocated to the parent process, making
execution more efficient.
Creating a process involves significant overhead because the Thread creation is lightweight since threads reuse the
OS must allocate seperate memory and resources. existing process resources, resulting in faster startup and
lower system cost.
Process communicate using Inter-Process Communication Threads communicate easily through shared variables and
(IPC) mechanisms such as pipes, sockets, shared memory, or objects, enabling faster and simpler communication.
message queues, which are complex and slower.
Processes are highly isolated from one another. A failure in Threads have low isolation. An error in one thread (eg.,
one process usually does not affect other processes. modifying shared data incorrectly) can impact other
threads in the same process.
Switching between processes requires saving and loading Thread context switching is faster and cheaper because
complete execution contexts, making context switching threads share the same memory and resources.
expensive.
Process provide better stability but are less efficient for Threads offer higher performance and are ideal for tasks
concurrent tasks. requiring parallel execution, such as servers and real-time
applications.

Eg., Running Chrome and MS Word simultaneously. Eg., Multiple tabs in Chrome, each handled by threads.

 When to Use Processes vs Threads


◦ Use Processes when you need strong isolation between different parts of an aplication. (Web Browsers like Chrome run each
tab as a separate process to ensure one crashing tab doesn’t affect others)
◦ Running completely independent tasks. (Image and video processing pipelines: Applications like Photoshop or video editors
use multiple processes to handle large computations separately)
◦ Leveraging multiple CPU cores for separate computational tasks. (Physics engines and AI computations in games run in separate
processes to utilize multiple CPU cores efficiently)

 Use Thread When


◦ You need to perform multiple tasks within the same application. (Mobile Apps: A messaging app like WhatsApp uses thread to
handle UI updates and background network requests simultaneously)
◦ Tasks need to share common data quickly. (Ecommerce platform: Websites like Amazon use threads to allow multiple users to
browse, add to cart, and checkout simultaneously while sharing inventory data)
◦ You want to improve responsiveness and performance of a single application. (Music Streaming Services: Apps like Spotify use
threads to keep the UI responsive while continuously buffering audio in the background)

 Key Features of Threads


◦ Concurrent Execution
▪ Multiple threads can run simultaneously, allowing programs to perform multiple tasks at once. Eg., In a web browser, one
thread can handle user interaction (scrolling, clicking), while another thread loads a web page in the background. This
prevents the UI from freezing while content is still loading.
◦ Resource Sharing
▪ Threads within the same process share memory and resources, making communication between threads efficient. Eg., In a
text editor like Microsoft Word, multiple threads handle different tasks – One thread checks spelling and grammar, and
another thread auto-saves the document, and another processes user input. Since all threads share the same document
data, resource sharing ensures efficiency without redundant memory usage.
◦ Lightweight
▪ Threads require fewer resources compared to creating multiple processes. Eg., In a multiplayer online game, multiple
threads manage player movement, background music, and network communication. Since creating a new process for
each task would be costly, using threads keeps the game smooth and responsive while consuming fewer resources.

 Why specifically Threads and not processes?


◦ Threads share memory space, making communication between them faster compared to processes.
◦ This ensures smooth and responsive performance without unnecessary duplication of resources.

 Creating Threads
◦ Extending the Thread Class
▪ The Thread class provides the foundation for creating and managing threads in Java. By extending this class, you can
override the run() method to define the code that will be executed in a separate thread.
class ThreadExample{
public static void main(String[] args) {
MyThread thread1 = new MyThread(); // create thread instance
MyThread thread2 = new MyThread(); // create another thread instance

[Link](); // start the first thread


[Link](); // start the second thread
}
}

class MyThread extends Thread {


// Override the run method to define thread behavior
@Override
public void run() {
for(int i=0; i<5; i++) {
// [Link]("Thread "+[Link]().getId()+" is running: "+i);
[Link]([Link]().getName()+" is running: "+i);

try {
[Link](500); // Pause execution for 500 milliseconds

} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}

/*
Thread-1 is running: 0
Thread-0 is running: 0
Thread-1 is running: 1
Thread-0 is running: 1
Thread-1 is running: 2
Thread-0 is running: 2
Thread-1 is running: 3
Thread-0 is running: 3
Thread-1 is running: 4
Thread-0 is running: 4
*/

▪ Advantages: Simpler to implement and direct access to Thread methods.


▪ Disadvantages: In Java, we can NOT extend two classes, but we can implement multiple interfaces. (Java does NOT support
multiple inheritance using classes, but it supports multiple inheritance through interfaces.)
Each task requires a new Thread instance.

◦ Implementing Runnable Interface


▪ The Runnable interface provides a more flexible approach to creating threads. It seperates the task from the thread itself,
promoting better object-oriented design and allowing a class to extend another class while still being runnable in a
separate thread.
class RunnableExample {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable(); // Create runnable instance

Thread thread1 = new Thread(runnable); // Create thread with runnable


Thread thread2 = new Thread(runnable); // Create another thread with same runnable

[Link](); // Start the first thread


[Link](); // Start the second thread
}
}

class MyRunnable implements Runnable {


// Implement the run method from Runnable interface
@Override
public void run() {
for(int i=0; i<5; i++) {
[Link]([Link]().getName()+" is running: "+i);
try {
[Link](500); // Pause execution for 500 milliseconds
} catch (InterruptedException e) { // Thrown when a thread is waiting, sleeping, or otherwise occupied, and the
thread is interrupted, either before or during the activity. Occasionally a method may wish to test whether the current
thread has been interrupted, and if so, to immediately throw this exception.
throw new RuntimeException(e);
}
}
}
}

/*
Thread-0 is running: 0
Thread-1 is running: 0
Thread-1 is running: 1
Thread-0 is running: 1
Thread-1 is running: 2
Thread-0 is running: 2
Thread-1 is running: 3
Thread-0 is running: 3
Thread-1 is running: 4
Thread-0 is running: 4
*/

▪ Advantages: Better object-oriented design and allows class to extend other classes.
Same Runnable instance can be shared across multiple threads.
▪ Disadvantages: Slightly more code to write and indirect access to Thread methods.

◦ Using Callable Interface


▪ The Callable interface, introdduced in Java 5 as part of the concurrency utilities, provides a more powerful alternative to
Runnable.
▪ Return values: Callable tasks can return results, unlike R unnable tasks which return void.
▪ Exception Handling: Callable’s call() method can throw checked exception, while Runnable’s run() method cannot.
▪ Future Objects: Callable works with future objects to retrieve results after task completion.






 s
Collection and Collection Framework

 Collection: If we want to represent a group of individual objects (called elements) as a single entity, then we should go for
Collection.
◦ It is a complete architecture to store and manipulate collections of objects.
◦ Located in [Link] package.
◦ It is used to storem retrieve, manipulate, and delete data easily.
◦ Eg., List, Set, Queue.
◦ Features:
▪ Can grow or shrink dynamically.
▪ Can store heterogeneous (different) tyoes of objects.
▪ Built-in methods for adding, removing, searching, sorting, etc.

◦ Collection framework: It defines several classes (implementations) and interfaces (rules) which can be used a group of objects
as single entity.
◦ A standardized set of interfaces and classes in Java to store and manage collections efficiently.
◦ Located in [Link] package.
◦ Provides interfaces, classes, and algorithms.

Java C++
Collection Container
Collection framework STL (Standard Template Library)






 Part

9-key interfaces of Colecton Framework

 Collection (I):
 If we want to represent a group of individual objects as a single entity then we should go for Collection.
▪ A Collection allows us to store multiple objects together in one container (like a bag or list).
▪ For example, instead of creating separate variables:
int a = 10;
int b = 20;
int c = 30;
▪ We can put them into one collection:
List<Integer> list = [Link](10, 20, 30);

 Collection interface defines the most common methods which are applicable for any Collection object.
▪ The Collection interface is the base (parent) interface for most data structures in Java.
▪ It defines common methods that every collection should have, such as:
 add()
 remove()
 size()
 clear()
 contains()
 Since different collection types (like List, Set, Queue) implement this interface, they all provide these basic
operations.

 In general collection framework is considered as root interface of Collection Framework. (There is no concrete class which
implements collection interface directly.)
▪ The Java Collection Framework has a hierarchy. At the top sits the Collection interface (like the family head). But no class
directly implements Collection.
Instead List, Set, and Queue extend the Collection interface. Classes like ArrayList, HashSet, and LinkedList implement those interfaces, not
Collection directly.

Collection (interface)
|
|--- List (interface)
| |--- ArrayList (class)
| |--- LinkedList (class)
|
|--- Set (interface)
| |--- HashSet (class)
| |--- TreeSet (class)

 List (I):

 List is a child interface of Collection (1.2v).

 If we want to represent a group of individual objects as a single entity where duplicates are allowed and insertion order
preserved then we should go for List.

 Used to store ordered collection of elements.

 Allows duplicate values.

 Supports index-based access (like arrays).

 Null values supported.

 Implementation: ArrayList (1.2v), LinkedList (1.2v), Vector, Stack. (Vector and Stack came in 1.0v, that’s why they are known as
Legacy classes – classes that existed before Java 1.2, before the modern Collection Framework. Vector and Stack classes are re-
engineer in 1.2v to implement list interface).

 Set (I):

 Child interface of Collection.



 If we want to represent a group of individual objects as a single entity where duplicates are not allowed and insertion order not
preserved then we should go for Set.

 Used to store unique elements.

 Represents unordered collection (except SortedSet/LinkedHashSet).


 Does not allow duplicates.

 Null values allowed, but only one.

 Implementation: HashSet (1.2v), LinkedHashSet (1.4v), TreeSet.

 Difference between List and Set



 Queue (I)

Collection (I) 1.2v → Queue 1.5v


→ PriorityQueue 1.5v
→ BlockingQueue 1.5v
→ LinkedBlockingQueue 1.5v
→ PriorityBlockingQueue 1.5v
 It is the child interface of Collection.
▪ Queue is an interface → cannot be instantiated directly.

 A Queue is a data structure that follows the FIFO – First In First Out. It means element inserted first is removed first.

 Eg.,
▪ People standing in a line at a ticket counter: The person who comes first gets served first. The last person waits until all
before them are served. This directly represents FIFO.
▪ Print Queue: When multiple documents are sent to printer, they are printed in the order they were submitted. The first
document entered is printed first.
▪ Task Scheduling in OS: Processes waiting for CPU time are stored in a queue. CPU picks the next process from the front.
Used heavily in OS scheduling algorithms.

 Queue is an interface in [Link] package. It extends the Collection interface.

 Queues are used when:


▪ Tasks should be processed in order
▪ Producer-consumer problems
▪ CPU scheduling
▪ Print spooling

public class Demo {


public static void main(String[] args) {
Queue<Integer> q = new LinkedList<>();

[Link](10);
[Link](20);
[Link](30);

[Link](q); // [10, 20, 30]

[Link]([Link]()); // 10
[Link]([Link]()); // 10 (removed)
[Link](q); // [20, 30]
}
}

 Priority Queue

▪ orders elements by natural ordering (min first for numbers)

import [Link].*;

public class PriorityQueueDemo {


public static void main(String[] args) {

PriorityQueue<Integer> pq = new PriorityQueue<>();

// ---- Adding elements ----


[Link](30); // throws exception if fails
[Link](10); // does not throw exception
[Link](20);

[Link]("Queue elements: " + pq);

// ---- Accessing head element ----


[Link]("peek(): " + [Link]()); // returns head, no removal
[Link]("element(): " + [Link]());// same but throws exception if empty

// ---- Removing elements ----


[Link]("poll(): " + [Link]()); // removes head, no exception
[Link]("remove(): " + [Link]()); // removes head, exception if empty

[Link]("Queue after removal: " + pq);

// ---- Iteration ----


[Link]("Iterating:");
for (Integer n : pq) {
[Link](n);
}
}
}
Queue elements: [10, 30, 20]
peek(): 10
element(): 10
poll(): 10
remove(): 20
Queue after removal: [30]
Iterating: 30
Process finished with exit code 0

 Blocking Queue
▪ waits (blocks) if queue is full (on insert) or empty (on removal).

import [Link].*;

public class BlockingQueueDemo {


public static void main(String[] args) throws InterruptedException {

BlockingQueue<String> bq = new ArrayBlockingQueue<>(2);


// ---- Insertion ----
[Link]("A"); // throws exception if full
[Link]("B"); // returns false if full

[Link]("Queue: " + bq);

// ---- offer with timeout ----


[Link]("offer(C, 2s): " + [Link]("C", 2, [Link])); // waits for space

// ---- Removing elements ----


[Link]("poll(): " + [Link]()); // removes head; returns null if empty
[Link]("take(): " + [Link]()); // blocks if empty

[Link]("Queue now: " + bq);

// ---- put() – waits if full ----


[Link]("X"); // blocks until spaceis available
[Link]("Y");

[Link]("After put(): " + bq);

// ---- remove() and element() ----


[Link]("remove(): " + [Link]()); // removes head; exception if empty
[Link]("element(): " + [Link]()); // head without removal; same like ‘remove’ but throws exception if empty

// ---- take() when empty ----


[Link](); // OK
[Link]("bq empty now");

// If [Link]() is called again, thread will block until an item is inserted


}
}
Queue: [A, B]
offer(C, 2s): false
poll(): A
take(): B
Queue now: []
After put(): [X, Y]
remove(): X
element(): Y
bq empty now
Process finished with exit code 0

 Map (I)

Map(I) 1.2v
|
|
______|_____________________________________________ Dictionary (AC) 1.0v
| | | | |
| | | | |
HashMap 1.2v WeakHashMap 1.2v IdentityHashMap 1.4v Hashtable 1.0v
| |
| |
LinkedHashMap Properties 1.0v

 Map is not the child interface of Collection. Belongs to [Link] package.

 If we want to represent a group of individual objects as key-value pairs, then should go for Map.

 Both key and value are objects. Keys are unique, but values can be duplicate.

 Used when we need fast lookup based on a key.

 Common Implementations:
▪ HashMap
 most commonly used
 no order guaranteed
 fast performance (O(1) average)
▪ LinkedHashMap
 maintains insertion order
▪ TreeMap
 stores keys in sorted order (based on natural ordering or Comparator)
▪ Hashtable
 synchronized (thread-safe)
 slower and legacy
 Common methods:
▪ put(k, v) → insert or replace a value
▪ get(k) → retrieve value
▪ remove(k) → delete mapping
▪ containsKey(k) → check if key exists
▪ containsValue(v) → check if value exists
▪ keySet() → returns all keys
▪ values() → returns all values
▪ entrySet() → returns key-value pairs

 SortedMap (I)

Map 1.2v
|
|
SortedMap 1.2v

 It is the child interface of map.

 If we want to represent a group of key value pairs according to some sorting order of keys then we should go for SortedMap.

 NavigableMap (I)

Map(I) 1.2v
|
|
SortedMap(I) 1.2v
|
|
NavigableMap(I) 1.6v
|
|
TreeMap 1.2v

 It is the child interface (or sub-interface) of SortedMap, it defines several utility methods for navigation urpose.

 Stores key-value in sorted order.

 Common methods:
▪ firstKey() → returns lower key
▪ lastKey() → returns highest key-value
▪ headMap(k) → keys strictly before given key-value
▪ tailMap() → keys greater or equal to given key
▪ subMap(fromKey, toKey) → keys greater or equal to given key
▪ reversed() → returns a reverse order view of this map

Collection Framework

Collection(I) 1.2v
|
|
____________________________|________________________
| | |
| | |
List(I) Set(I) Queue(I) 1.5v
| | |
| | |
________|_________ ____|____ ____|____
| | | | | | |
AL LL Vector 1.0v | | | |
| HashSet SortedSet(I) PQ 1.5v BQ 1.5v
| | | |
Stack 1.0v | | |
LHS NavigableSet(I) 1.6v ____|____
1.4v | | |
| | |
TreeSet PBQ LBQ
1.5v 1.5v

Map(I) 1.2v
|
| 1.0v
______|_________________________________________________ Dictionary(AC)
| | | | | |
| | | | | |
HashMap WeakedHashMap IdentityHashMap SortedMap(I) Hashtable 1.0v
| 1.4v | |
| | |
LinkedHashMap 1.4v 1.6v NavigableMap(I) Properties 1.0v
|
|
TreeMap

 Sorting:
Comparable Comparator
Purpose Used for default (natural) sorting of Used for custom/multiple sorting logics.
objects.
Package Available in [Link] package. Available in [Link] package
Method public int compareTo(T o) public int compare(T o1, T o2)
How many sort orders? Only one sorting logic (inside the class Multiple sorting logics possible (outside
itself). the class).
Where is the logic written? Inside the same class of the object being In a separate class OR via lambda.
sorted.
Used when When class has a natural order (eg., When you want different ways to sort
Integer, String). same objects (eg., by name, by age).
Real-life analogy Your Aadhaar card number: fixed, single Filters on Amazon: sort by price,
identity. popularity, rating – multiple options.

Sort students by age using Comparable (Natural sorting)

import [Link];
import [Link];
import [Link];

class Student implements Comparable<Student>{ // Class 'Student' must either be declared abstract or implement abstract method
'compareTo(T)' in 'Comparable'
int age;
String name;
Student(int age, String name) {
[Link] = age;
[Link] = name;
}

@Override
public int compareTo(Student student) {
return [Link] - [Link];
}

@Override
public String toString() {
return age+ " " +name;
}
}

public class ComparableDemo {


public static void main(String[] args) {
List<Student> list = new ArrayList<>();
[Link](new Student(33, "Satyam Singh"));
[Link](new Student(30, "Shashank Ojha"));
[Link](new Student(2, "Aaakash Ghorpade"));

[Link](list); // uses compareTo(), or it will show error. First add 'implements Comparable for Student' to Student class
then add 'compareTo()'
// Java is saying: “Student does NOT implement Comparable in a way that matches what [Link]() needs.”

[Link]("Sorted by Age, using Comparable: "+list); // OUTPUT: Sorted by Age, using Comparable: [2 Aaakash
Ghorpade, 30 Shashank Ojha, 33 Satyam Singh]
}
}

Sort students by name or by age using different comparators (Custom Sorting)

import [Link];
import [Link];
import [Link];
import [Link];

class Student{
int age;
String name;
Student(int age, String name) {
[Link] = age;
[Link] = name;
}

@Override
public String toString() {
return age+ " " +name;
}
}

public class ComparatorDemo {


public static void main(String[] args) {
List<Student> list = new ArrayList<>();
[Link](new Student(33, "Satyam Singh"));
[Link](new Student(30, "Shashank Ojha"));
[Link](new Student(2, "Aaakash Ghorpade"));

// Comparator for sorting by name


Comparator<Student> sortByName = (s1, s2) -> [Link]([Link]);

// Comparator for sorting by age


Comparator<Student> sortByAge = (s1, s2) -> [Link] - [Link];

[Link]("Sorted by Name:");
[Link](list, sortByName);
[Link](list);

[Link]("Sorted by Age:");
[Link](list, sortByAge);
[Link](list);
/*
OUTPUT:
Sorted by Name:
[2 Aaakash Ghorpade, 33 Satyam Singh, 30 Shashank Ojha]
Sorted by Age:
[2 Aaakash Ghorpade, 30 Shashank Ojha, 33 Satyam Singh]
*/
}
}
 Cursors
Enumeration Iterator ListIterator
Used for Legacy classes only (Vector, All Collection classes (List, Set, List implementations only
Hashtable) Queue, etc) (ArrayList, LinkedList)
Methods HasMoreElements(), HasNext(), next(), remove() HasNext(), next(),
nextElement() hasPrevious(), previous(), add(),
set(), remove()
Features Read-only (cannot remove Read + remove; one-directional Read + modify (add, remove,
elements); very old (from JDK → forward only; Failfast → set); bidirectional traversal
1.0); throws (forward + backward)
ConcurrentModificationExcepti
on

 Utility class:
 A utility class that provides static methods to operate on Collection objects (List, Set)





 s

Collection Interface

 Collection(I) → If we want to represent a group of individual objects as a single entity then we should go for Collection.

 In general, collection interface is considered as root interface of Collection framework.

 Collection interface defines the most common methods which are applicable for any collection object.

Methods Descrption
boolean add(Object o) Add an object or element
boolean addAll(Collection c) Add group of objects
boolean remove(Object o) Remove a particular pbject
boolean removeAll(Collection c) Remove group of objects
void clear() Remove all objects
boolean retainAll(Collection c) To remove all objects except those present in c
boolean isEmpty() Checks whether my Collection is empty or not
int size() No. of elements
boolean contains(Object o) Particular object is available or not
boolean containsAll(Collection c) Group of objects available or not
Object[] a = [Link](); Convert Collection to array
Iterator iterator() To get objects one by one

 Collection interface does not contain any method to retrieve objects, there is no concrete class which implements collection class
directly.

List Interface

 Part of [Link] package and child interface of Collection interface.

 If we want to represent a group of individual objects as a single entity where duplicates are allowed and insertion order must be
preserved then we should go for List.

 We can differentiate duplicates by using index.


 We can preserve insertion order by using index, hence index play very important role in list interface.

Methods Description
void add(int index, Object o) Insert object at specified index
boolean addAll(int index, Collection c) Add group od objects from the specified index
Object get(int index) Get element of a particular index
Object remove(int index) Remove element from the given index
Object set(int index, Object new) To replace the element present at specified index with provided
Object and returns old object
int indexOf(Object o) Returns index of first occurrence of ‘o’
int lastIndexOf(Object o) Returns index of last occurrence of ‘o’
ListIterator listIterator(); Bidirectional traversal

ArrayList

 The underlined data structure resizable (dynamic) array or growable array.

 Duplicates are allowed.

 Insertion order is preserved.

 Heterogeneous objects are allowed, except TreeSet & TreeMap everywhere heterogeneous objects are allowed.

 Null insertion is possible.

 Constructors:
◦ ArrayList<Object> list = new ArrayList<>(); → No-arg Constructor
▪ creates an empty ArrayList object with default initial capacity = 10. Once ArrayList reaches its max capacity a new
ArrayList will be created with newCapacity = (oldCapacity * 3/2)+1. This is why ArrayList provides dynamic resizing.

◦ ArrayList l = new Arrayist(int initialCapacity);


▪ Creates an ArrayList with a given initial capacity.
▪ Useful when you know in advance roughly how many elements you will store → helps avoid resizing overhead.
▪ If an invalid (negative) capacity is passed → throws IllegalArgumentException.

◦ ArrayList l = new ArrayList(Collection c);


▪ Creates a new ArrayList containing all elements of the given collection.
▪ Used when you want an equivalent ArrayList of LinkedList, HashSet, Vector, TreeSet, or any other Collection.
List<Student> list = new ArrayList<>();
[Link](new Student(33, "Satyam Singh"));
[Link](new Student(30, "Shashank Ojha"));
[Link](new Student(2, "Aaakash Ghorpade"));

ArrayList<Student> list2 = new ArrayList<>(list); // Contents of collection 'list2' are updated, but never queried

 Example for ArrayList:


import [Link];

class ArrayListDemo {
public static void main(String[] args) {
ArrayList list = new ArrayList();
[Link]("A");
[Link](10);
[Link]("A");
[Link](null);
[Link](list);
[Link](2);
[Link](list);
[Link](2, "M");
[Link]("N");
[Link](list);
}
}
/*
OUTPUT
[A, 10, A, null]
[A, 10, null]
[A, 10, M, null, N]
*/

 Why Collections implement Serializable and Cloneable?


◦ In Java, most standard Collection classes (like ArrayList, LinkedList HashSet, Vector, etc.) implement Serializable and Cloneable
for the following reasons:
▪ Serializable – for Object transfer
 Collections are often used to:
◦ store objects,
◦ transfer them between layers/modules,
◦ save them to disk,
◦ send them over a network (RMI, sockets),
◦ store them in distributed caches (Redis, Hazlecast, Infinispan).
 Usually we use Collections to hold and transfer objects from one layer to another. To support this requiremnt, most
Java Collection classes implement Serializable, so that the entire collection can be serialized.

▪ Cloneable – for making copies of Collections


 Many Java Collections need to support clone() because:
◦ Users may want an independent copy of the collections.
◦ It helps in woring with temporary buffers.
◦ Used in concurrency (snapshot copies)

 RandomAccess Interface
◦ RandomAccess is a marker interface in [Link] package. It contains no methods.
public interface RandomAccess { }

◦ It is used to mark a List implementation as supporting fast (generally O(1)) random access, i.e., fast indexing: [Link](i)

◦ Different list implementations have different performance characteristics:


▪ ArrayList → fast random access
get(index) = O(1)
▪ LinkedList → slow random access
get(index) = O(n)
▪ The RandomAccess interface gives algorithms a way to check performance capability at runtime.

◦ ArrayList, Vector, and Stack classes implements RandomAccess interface, so that we can access any random element with the
same speed.

◦ Hence if our frequent operation is retrieval operation then ArrayList is the best choice.

 Example for Serialization, Cloneable, and RandomAccess Interface:


import [Link];
import [Link];
import [Link];
import [Link];

class ArrayListDemo {
public static void main(String[] args) {
ArrayList list1 = new ArrayList();
LinkedList list2 = new LinkedList();
[Link](list1 instanceof Serializable);
[Link](list2 instanceof Serializable);
[Link](list1 instanceof Cloneable); // [Link] package
[Link](list2 instanceof Cloneable);
[Link](list1 instanceof RandomAccess);
[Link](list2 instanceof RandomAccess);
}
}
/*
OUTPUT
true
true
true
true
true
false
*/

 ArrayList is best choice if our frequent operation is retrieval operation, because ArrayList implements RandomAccess interfaces.

 ArrayList is the worst choice if our frequent operation is insertion oe deletion in the middle, because several shift operation are
require.

Difference between ArrayList and Vector

ArrayList Vector
Synchronization Not synchronized. Every method is synchronized.
(Every method present in ArrayList is non- (Most of the methods present in the
synchronized.) Vector are synchronized methods.)
Thread-safe At a time multiple threads are allowed to At a time only one thread is allowed to
operate on ArrayList object and hence operate on Vector object is thread-safe.
ArrayList is not thread safe.
Performance All threads allowed to operate Threads are required to wait to operate on
simultaneously → threads are not Vector object and hence relatively
required to wait to operate on ArrayList, performance is low.
hence relatively performaance is high
Growth Mechanism (Capacity Increment) When full → newCapacity = (oldCapacity When full,
* 3/2)+1 If no increment provided → newCapacity
= oldCapacity * 2 (double)
If increment provided → added as per
increment value
Legacy or Modern Class Introduced in Java 1.2 as a part of modern Introduced in Java 1.0 → considered
Collections framework. legacy → retrofitted to Collection
Framework in Java 1.2
Iterator type Uses Iterator Supports Ierator, as well as Enumeration
(old, legacy)
Multi-threading Uses in single-threaded programs, and Orginally designed for multi-threading. But
Multi-threading with external today, CopyOnWriteArrayList and
synchronization. ConcurrentHashMap are preferred.

 How to get Synchronized version of ArrayList?

 ArrayList list1 = new ArrayList();


List list = [Link](list1);
ArrayList is not synchronized by default. Using [Link](list1) you get a thread-safe wrapper around it. list1 remains non-
synchronized, while list becomes synchronized and can be safely used in multi-threaded environments.
public static List synchronizedSet(List list);

 Even though list is synchronized, when iterating you must manually synchronize:
synchronized(list) {
Iterator it = [Link]();
while([Link]()) {
[Link]([Link]());
}
}
Because iterator() is not thread-safe.

 Set set = new HashSet();


Set synchronizedSet = [Link](set);

 public static Set synchronizedSet(Set s);

LinkedList

 LinkedList is a linear data structure in Java that stores elements as nodes, where each node contains:
◦ Data
◦ Pointer/reference to the next node
◦ (In doubly linked list) Pointer to the previous node
Java’s LinkedList is a Doubly Linked List implementation and is part of [Link] package. → The underlying data structure is Doubly Linked List.

 Features:
◦ Uses nodes instead of contiguous memory → no memory wastage
◦ Good for insertion/deletion at beginning or middle.
◦ Insertion order is preserved.
◦ Poor performance for searching (linear time).
◦ Duplicates are allowed.
◦ Heterogeneous Objects are allowed.
◦ Null insertion is possible.
◦ LinkedList implements Serializable and Clonable interfaces but not RandomAccess interface.

import [Link];

public class LinkedListImplementation {


public static void main(String[] args) {
LinkedList<Object> list = new LinkedList<>();
// Adding elements
[Link]("A");
[Link]("a");
[Link]("A");
[Link](1234);
[Link](2,"Rahul");
[Link](null);
// [Link](list); // [a, A, Rahul, A, 1234, null]

// Accessing elements
[Link]([Link](0)); // a
[Link]([Link]()); // a
[Link]([Link]()); // null

// Removing elements
[Link]();
[Link](list); // [A, Rahul, A, 1234, null]
[Link]();
[Link](list); // [Rahul, A, 1234, null]
[Link]();
[Link](list); // [Rahul, A, 1234]
[Link](2);
[Link](list); // [Rahul, A]
[Link]("A");
[Link](list); // [Rahul]

// Queue operations
[Link]("X"); // add element
[Link](list); // [Rahul, X]
[Link](); // removes head
[Link](list); // [X]
[Link]([Link]()); // view head i.e, X

//Deque operations
[Link]("Y");
[Link](list); // [Y, X]
[Link]("Z");
[Link](list); // [Y, X, Z]
[Link]([Link]()); // Y
[Link]([Link]()); // Z
}
}

 Usually we can use LinkedList to implement Stack and Queue to provide support for this requirement LinkedList class defines
following specific methods.
void addFirst();
void addLast();
Object getFirst();
Object getLast();
Object removeFirst();
Object removeLast();
 Constructors
LinkedList l = new LinkedList();
▪ creates an empty LinkedList Object
LinkedList l1 = new LinkedList(Collection c);
▪ creates an equivalent LinkedList Object for the given Collection

Differences between ArrayList and LinkedList

ArrayList LinkedList
Internal Data Structure Internally uses a dynamic array. Internally uses a doubly linked list.
Elements stored in contiguous memory. Elements stored as nodes, each node has
data, pointer to previous, and pointer to
next.
Accessing elements (Random Access) Very fast because it uses index-based Slow because traversal starts from
access. beginning or end. O(n)
Directly jumps to memory location. O(1)
Insertion/Deletion Slow for insertion/deletion in middle or Fast for insertion/deletion at beginning or
beginning. middle.
Because elements must be shifted. Just update node pointers.
Eg., Inserting at index 0 → shift everthing O(1) → for beginning/end
right O(n) O(n) → for middle (because traversal
needed)
Cache Performance Better cache locality (contiguous memory) Poor cache locality (scattered nodes)
→ Faster iteration

 Vector

 Introduced in JDK 1.0. Since Java 2 (JDK 1.2), Vector was updated to implement the List interface.

 Vector class implements a growable array of objects.

 Similar to an array: elements are accessed using an integer index. Vector implements RandomAccess interface.

 Unlike arrays, the size of Vector can dynamically grow or shrink based on additions or removals.

 Vector implements Serializable, Cloneable, Iterable<E>, Collection<E>, and List<E>.

 Allows duplicates, and null values.

 Insertion order is preserved.

 Heterogenous objects are allowed but not recommended in practice.

 Each Vector maintains:


◦ capacity → total storage available
◦ capacityIncrement → the amount by which capacity grows.
Capacity is always >=size of the Vector. When elements are added beyond current capacity, storage expands in chunks of capacityIncrement.
Applications can increase capacity beforhand to avoid multiple reallocations.

 Vector is synchronized by default (most of the methods present in Vector are synchronized) → thread-safe. However, due to
synchronization overhead:
◦ If thread-safety is not required, prefer ArrayList over Vector.

 Best choice if the frequent operation is retrieval.

 Methods

add(Object o) ← from Collection Appends the specified element to the Vector.


add(int index, Object o) ← from List Insert an element at the specified position.
addElement(Object o) ← from Vector Adds an element to the Vector (legacy method).
remove(Object o) ← Collection Remove the first occurrence of the specified element.
removeElement(Object o) ← Vector Remove the first occurrence of the specified element (legacy).
remove(int index) ← List Remove element at the specified index.
removeElementAt(int index) ← Vector Remove element at the specified index (legacy).
Clear() ← Collection Removes all elements from the Vector.
RemoveAllElements() ← Vector Removes all elements (legacy equivalent to clear() )
Object get(int index) ← List Returns the element at the specified index.
Object elementAt(int index) ← Vector Returns the element at the given index (legacy).
Object firstElement() ← Vector Returns the first element of the Vector.
Object lastElement() ← Vector Returns the last element of the Vector.
Object set(int index, E element) Replaces the element at the specified position in the Vector with
the specified element.
Object[] toArray() Returns an array containing all of the elements in the Vector in
the correct order.

 Vector class contructors


◦ Vector v = new Vector();
▪ Creates a Vector with default initial capacity = 10. If the Vector becomes full, a new Vector is created with,
newCapacity = 2 × currentCapacity
Elements from the old Vector are copied into the new one.
◦ Vector v = new Vector(int initialCapacity);
▪ Creates an empty Vector with the specified initial capacity.
◦ Vector v = new Vector(int initialCapacity, int incrementalCapacity);
▪ Creates a Vector with given initial capacity and a custom incremental capacity.
▪ Capacity grows by incrementalCapacity instead of doubling.
◦ Vector v = new Vector(Collection c);
▪ Creates a Vector containing all elements of the given Collection.
▪ Order is preserved.

import [Link];

public class VectorExample {


public static void main(String[] args) {
Vector v = new Vector();
[Link]([Link]()); // 10

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


[Link](i);
}

[Link]([Link]()); // 10
[Link]("A");
[Link]([Link]()); // 20
[Link](v); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, A]
}
}

import [Link];

public class VectorExample2 {


public static void main(String[] args) {
Vector v = new Vector(25);
[Link]([Link]()); // 25

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


[Link](i);
}
[Link]([Link]()); // 25
[Link]("A");
[Link]([Link]()); // 25
[Link](v); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, A]
}
}
import [Link];

public class VectorExample {


public static void main(String[] args) {
Vector v = new Vector(10, 5);
[Link]([Link]()); // 10

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


[Link](i);
}
[Link]([Link]()); // 10
[Link]("A");
[Link]([Link]()); // 15
[Link](v); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, A]
}
}
Stack

[Link]
↳ [Link]<E>
↳ [Link]<E>
↳ [Link]<E>
↳ [Link]<E>

Stack inherits Serializable, Cloneable, Iterable<E>, Collection<E>, List<E>, and RandomAccess interfaces.

 Stack represents a Last-In-First-Out (LIFO) data structure.

 Extends Vector,meaning:
◦ It is synchronized.
◦ Allows null, duplicates, insertion order, and heterogeneous objects (although generics are recommended).

 When a stack is created, it is initially empty. As Stack extends Vector:


◦ It is thread-safe but slower due to synchronization overhead.
◦ Capacity management, fail-fast iterators, etc., behave the same as Vector.

 Constructor:
◦ Stack s = new Stack();
▪ Creates an empty Stack.
▪ Internally uses Vector’s default constructor.
▪ Initial capacity of the underlying Vector = 10 (inherited from Vector).
▪ The stack grows dynamically as elements are pushed.
▪ After creation, the stack contains no items.

 Methods

push(Object o) Inserts an item onto the top of the stack.


pop() Removes and returns the top-most element of the stack. Throws
EmptyStackException if the stack is empty.
peek() Returns (but does not remove) the top element of the stack.
Throws EmptyStackException if the stack is empty.
empty() Returns true if the stack contains no items, otherwise false.
search(Object o) → Offset Returns the 1-based position of the element from the top of the
stack; returns -1 if not found.

import [Link];

public class StackExample {


public static void main(String[] args) {
Stack stk = new Stack();
[Link]([Link]()); // true
[Link]("A");
[Link]("B");
[Link]("C");
[Link](stk); // [A, B, C]
[Link]([Link]()); // false
[Link]();
[Link](stk); // [A, B]
[Link]([Link]("A")); // 2
[Link]([Link]("B")); // 1
[Link]([Link]("C")); // -1
}
}

Three cursors of Java

 In Java, a cursor is an object used to traverse (iterate) through the elements of a collection.

 Java provides three types of cursors:


1. Enumeration (Legacy Cursor)
▪ Introduced in JDK 1.0 (for Legacy).
▪ Helps retrieve objects one by one from old collection objects (Legacy Collections).
▪ Characteristics:
 Read-only (only forward movement)
 Cannot remove elements
 Not fail-fast
 Slow and outdated
▪ We can create Enumeration Object by using elements() method of Vector class.
Enumeration e = [Link]();
▪ Used with Legacy classes like Vector, Stack, and Hashtable.
▪ Methods:
boolean hasMoreElements() Checks whether more elements are present in the legacy
collection.
Returns true if another element exists, otherwise false.
Helps avoid NoSuchElementException.
Object nextElement() Returns the next element from the collection.
Should be used only when hasMoreElements() is true.

import [Link];
import [Link];

public class EnumerationExample {


public static void main(String[] args) {
Vector v = new Vector();
for(int i=0; i<=10; i++) {
[Link](i);
}
[Link](v); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Enumeration e = [Link]();
while([Link]()) {
Integer I = (Integer) [Link](); // Object to Integer
if(I%2==0) {
[Link](I+" ");
}
} // 0 2 4 6 8 10
}
}

2. Iterator (Universal Cursor)


▪ Introduced in JDK 1.2
▪ Used with all Collection classes (List, Set, Queue, etc.)
▪ Characteristics:
 Forward-only
 Supports remove()
 Fail-fast (throws ConcurrentModificationException)
▪ Iterator it = [Link]();
▪ Methods:
boolean hasNext() Checks if there is another element in the collection.
Returns true if next element exists.
Object next() Retrieves the next element and advances the iterator.
Throws NoSuchElementException if used without checking
hasNext().
void remove() Removes the current element (the last element returned by
next()).
Prevents ConcurrentModificationException (when used
properly).

import [Link];
import [Link];
import [Link];

public class IteratorExample {


public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i=0; i<=10; i++) {
[Link](i);
}
[Link](list); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Iterator itr = [Link](); // creates iterator for the list (allows traversal of the list one element at a time)
while([Link]()) { // checks whether there is a next element or not; prevents going out of bound
Integer I = (Integer) [Link](); // retrieves next element from the list
if(I%3==0) {
[Link](I+" "); // 0 3 6 9
} else [Link]();
}
}
}

3. ListIterator (Bidirectional Cursor)


▪ Introduced in JDK 1.2
▪ Used with only List implementations (ArrayList, LinkedList, Vector, Stack).
 ListIterator is the most powerful cursor but its limitation is, it is applicable only for List implemented class objects and
it is not a universal cursor.
▪ ListIterator is the child interface of Iterator and hence all methods of Iterator by default available to ListIterator.
▪ Characteristics:
 Can move forward and backward
 Allows add, remove, replace
 Supports fail-fast
▪ ListIterator lt = [Link]();
▪ Methods:
boolean hasNext() Checks if there is a next element when moving forward.
Object next() Moves the cursor forward and returns the next element.
int nextIndex()
boolean hasPrevious() Checks if there is an element before the current cursor position.
Object previous() Moves the cursor backward and returns the previous element.

int previousIndex()

void add(Object o) Inserts a new element at the current cursor position.


void remove() Removes the last element returned by next() or previous().
void set(Object o) Replaces the last element returned by next() or previous() with a
new value.

import [Link];
import [Link];

public class ListIteratorImplentation {


public static void main(String[] args) {
LinkedList ll = new LinkedList();
[Link]("Balakrishna");
[Link]("Venki");
[Link]("Chiran");
[Link]("Nag");
[Link](ll); // [Balakrishna, Venki, Chiran, Nag]

ListIterator ltr = [Link]();


while([Link]()) {
String s = (String) [Link]();
if([Link]("Venki")) {
[Link]();
} else if([Link]("Nag")) {
[Link]("Chaitu");
} else if([Link]("Chiran")) {
[Link]("Charan");
}
}
[Link](ll); // [Balakrishna, Charan, Nag, Chaitu]
}
}
Comparison of the three cursors

Enumeration Iterator ListIterator


Applicable for Only legacy classes Any Collection class Only List classes
Movement Only forward (Single direction Only forward (Single direction Both forward and backward
cursor) cursor) (Bi-directional cursor)
Accessibility Only read access Both Read and remove Read, remove, replace and
addition of new object
How to get it? By using elements() method of By using iterator() method of By using listIterator() method
Vector class Collection interface of List interface
Methods 2 methods 3 methods 9 methods
hasMoreElements(), hasNext(),
nextElement() next(),
remove()
Is it Legacy? Yes (1.0v) No (1.2v) No (1.2v)

Implementation Classes of the three Cursors

import [Link].*;

class CursorDemo {
public static void main(String[] args) {

Vector v = new Vector();

Enumeration e = [Link]();
Iterator itr = [Link]();
ListIterator ltr = [Link]();

[Link]([Link]().getName()); // [Link]$1
[Link]([Link]().getName()); // [Link]$Itr
[Link]([Link]().getName()); // [Link]$ListItr
}
}
Java uses inner classes to implement cursor logic:
◦ Vector$1 → Anonymous inner class implementing Enumeration
◦ Vector$Itr → Inner class implementing Iterator
◦ Vector$ListItr → Inner class implementing ListIterator

Set (I)

Collection(I) 1.2v
|
|
____________________________|________________________
| | |
| | |
List(I) Set(I) 1.2v Queue(I) 1.5v
|
|
_______|______
| |
| |
HashSet 1.2v SortedSet(I) 1.2v
| |
| |
LinkedHashSet NavigableSet(I) 1.6v
1.4v |
|
TreeSet 1.2v

 Set is a child interface of Collection.


 If we want to represent a group of individual objects as a single entity, where duplicates are not allowed and insertion order is not
preserved then we should go for Set.

 Set interface doesn’t contain any new methods. SO we have to use only Collection interface methods.

HashSet

 HashSet is a class in Java that implements the Set interface and stores elements using a hash table.

 Duplicates are not allowed. If we are trying to insert duplicates, we won’t get any compile-time or run-time errors. add() method
simply returns false.

 Insertion order is not preserved and all objects will be inserted based on hash-code of objects. (No guaranteed order - elements
appear in random order)

 Null value allowed (only one)

 Heterogenous objects are allowed.

 Implements Serializable and Clonable interfaces but not RandomAccess.

 HashSet is the best choice, if our frequent operation is Search operation.

 Constructors (constructors are common for HashSet, LinkedHashSet, HashMap, IdentityHashMap, WeakHashMap, Hashtable)
◦ HashSet h = new HashSet();
▪ Creates an empty HashSet. Internally creates a HashMap with default initial capacity = 16, and default load factor = 0.75.
▪ What does load factor mean?
 HashSet grows when it becomes 75% full. Means 16*0.75=12 → When 12 elements are inserted, HashSet resizes to
maintain performance.

◦ HashSet h = new HashSet(int initialCapacity);


▪ Creates HashSet with specified initial capacity. Load factor remains default = 0.75.
▪ To avoid rehashing if you know the approximate size beforehand.

◦ HashSet h = new HashSet(int initialCapacity, float loadFactor);


▪ Creates HashSet with custom initial capacity and custom load factor.
▪ Eg.,
HashSet<String> set = new HashSet<>(50, 0.90f);
This means resize occurs only when 90% full.

◦ HashSet h = new HashSet(Collection c);


▪ Creates HashSet and initializes it with the elements of the given Collection.
▪ Removes duplicates automatically. New set size will be equal to unique elements in the collection.
▪ Eg.,
ArrayList<Integer> list = new ArrayList<>([Link](10, 20, 20, 30));
HashSet<Integer> set = new HashSet<>(list);

import [Link];

public class HashSetExample {


public static void main(String[] args) {
HashSet set = new HashSet();
[Link]("Apple");
[Link]("Banana");
[Link]("Mango");
[Link](123);
[Link](null);
[Link](null); // allowed only once
[Link]("Apple"); // duplicate -> ignored

[Link](set); // [null, Apple, Mango, 123, Banana]


[Link]([Link]("Apple")); // true
[Link]([Link]("Grapes")); // false
[Link]("Banana");
[Link](set); // [null, Apple, Mango, 123]
[Link]([Link]()); // 4
}
}
LinkedHashSet

 LinkedHashSet is a Set implementation that does not allow duplicates, maintains insertion order, uses hashtable + doubly linked
list, and allows one null value. (It is a child class of HashSet, but it adds a linked list to preserve order)

 Internally it uses HashMap for fast search, and doubly linked list for remembering insertion order.

import [Link];
import [Link];

public class HashSetExample {


public static void main(String[] args) {
HashSet set = new LinkedHashSet();
[Link]("Apple");
[Link]("Banana");
[Link]("Mango");
[Link](123);
[Link](null);
[Link](null); // allowed only once
[Link]("Apple"); // duplicate -> ignored
[Link](set); // [Apple, Banana, Mango, 123, null]
}
}

 LinkedHashSet is the best choice to develop cache based applications, where duplicates are not allowed and insertion order must be
preserved.

SortedSet

 It is the child interface of Set.

 If we want to represent a group of individual objects according to some sorting order and duplicates are not allowed then we should
go for SortedSet.

 Methods of SortedSet:
first() Returns smallest element
last() Returns largest element
handSet(toElement) elements < toElement
tailSet(fromElement) elements >= fromElement
subSet(from, to) fromElement <= elements < toElement
comparator() Returns custom comparator (or null if natural ordering)

Default natural sorting order for numbers – ascending order and for String – alphabetical order.
We can apply the above methods only on SortedSet implemented class objects. That is on the TreeSet object.

TreeSet

 TreeSet is implemented using a TreeMap, and TreeMap uses a Red-Black Tree, which is a type of self-balancing BST. So TreeSet
always keeps elements sorted.

 TreeSet implements Set interface → duplicates automatically rejected.

 Elements are stored according to sorting order, not according to the order of insertion (Insertion order NOT preserved). Order is
natural ordering (ie., integers ascending) or custom ordering (Comparator).

 Heterogeneous Objects are NOT allowed


◦ TreeSet compares elements using compareTo().
◦ If you insert different types, like:
TreeSet set = new TreeSet();
[Link]("A");
[Link](10); // ❌ Heterogeneous → ClassCastException
It will throw [Link], because Java cannot compare “A” with 10.

 TreeSet does NOT allow null. Before Java 7, TreeSet allowed a single null when using a custom Comparator. Java 7+, natural ordering
does NOT allow null. Adding null throws NullPointerException.
TreeSet<String> set = new TreeSet<>();
[Link](null); // ❌ NullPointerException




 s
Even numbers elements get filtered and its square is stored
Map ----> stream, map, collect
Filter -----> stream, filter, collect
Sorted ----> stream, sorted, collect

Filter names that start with 'J', have at least length 4, convert to uppercase, and sort alphabetically using Java Streams.

import [Link].*;
import [Link].*;

public class StreamFilterExample {


public static void main(String[] args) {
List<String> names = [Link]("John", "Jane", "Jack", "Doe", "Dane");

List<String> result = [Link]()


.filter(name -> [Link]("J")) // starts with J
.filter(name -> [Link]() >= 4) // length >= 4
.map(String::toUpperCase) // convert to uppercase
.sorted() // sort alphabetically
.collect([Link]()); // collect to list

[Link](result);
}
}
[JACK, JANE, JOHN]

[JACK, JANE, JOHN]

[Link] -> returns the same value as an input


Strategy Design Pattern

 The Strategy Pattern lets you define a family of algorithms, put each one in a separate class, and make them interchangeable at
runtime. It helps achieve loose coupling by depending on abstraction (interface) instead of concrete implementations.

Loose and Tight Coupling

 Loose coupling and tight coupling describe how strongly different parts (modules, classes, services, systems) depend on each other
—commonly used in software engineering, systems design, and even organizations.

 Tight Coupling
◦ Components are highly dependent on each other.
◦ Characteristics
▪ One component knows a lot about another
▪ Changes in one part often force changes in others
▪ Harder to test, modify, or reuse
▪ Faster to build initially, but harder to maintain
◦ Eg.,
class Car {
Engine engine = new Engine(); // directly creates Engine
}
▪ Here, Car is tightly coupled to Engine. If Engine changes, Car may break.

 Loose Coupling
◦ Components are minimally dependent on each other.
◦ Characteristics
▪ Components interact through interfaces or contracts
▪ Changes in one component don’t affect others much
▪ Easier to test, replace, scale, and maintain
▪ Preferred in large systems and microservices
◦ Eg.,
class Car {
Engine engine;
Car(Engine engine) {
[Link] = engine;
}
}
▪ Now Car depends on an interface or abstraction, not a specific Engine.

 Tight Coupling Example


Create classes:
◦ NotificationService → manages sending notifications
◦ UserService → manages user operations and directly depends on NotificationService
◦ App → triggers the flow and receives the notification output

public class NotificationService {


public void send(String message) {
[Link]("Notification: "+message);
}
}

public class UserService {


NotificationService notificationService = new NotificationService();
public void notifyUser(String message) {

// user related logic


[Link]("Hello Satyam, your action was successful");
}
}

public class App {


static void main() {
UserService userService = new UserService();
[Link]("Order placed");
}
}

/*
OUTPUT
Notification: Hello Satyam, your action was successful
*/

◦ Why this is still tight coupling


▪ UserService is locked to NotificationService.
▪ It depends on a concrete class, not an abstraction.
 A concrete class is a real, fully implemented class that can be instantiated using new.
public class UserService {
NotificationService notificationService = new NotificationService();
}
Here, NotificationService is a concrete class. The class has actual implementation details.
 An abstraction is something that defines what should be done, not how it is done. In Java, abstractions are usually:
interface, and abstract class.
▪ Changing notification logic (SMS, Email, Push) requires modifying UserService.
▪ Any change requires modifying UserService code.
◦ Tight Coupling: NotificationService is used directly inside UserService.

 Loose Coupling Example


NotificationService (Interface) → defines what to do, not how to do it
package loose;

public interface NotificationService {


//abstract method - no definition
void send(String message);
}

EmailNotificationService (Implementation) → one possible way of sending notifications


package loose;

public class EmailNotificationService implements NotificationService{


@Override
public void send(String message) {
[Link]("Email notification: "+message);
}
}

UserService → depends on abstraction, not concrete implementation


package loose;

public class UserService {


private NotificationService notificationService;

// Dependency Injection via constructor


UserService(NotificationService notificationService) {
[Link] = notificationService;
}

public void processUserAction() {


// User related logic
[Link]("Hello Satyam, your action was successful");
}
}

App → decides which notification service to use


import [Link];
import [Link];
import [Link];

public class App {


static void main() {
// tight
// UserService userService = new UserService();
// [Link]("Order placed");

// loose
NotificationService notificationService = new EmailNotificationService();
[Link] userService1 = new [Link](notificationService);
[Link]();
}
}

/*
OUTPUT
Email notification: Hello Satyam, your action was successful
*/

◦ Why this us Loose Coupling?


▪ UserService does not know how notification is sent
▪ You can switch implementations without touching UserService
▪ Easy to add SMSNotificationService, and PushNotificationService
▪ Easy to unit test (mock the interface)












 s
Spring Initializr

 [Link] (boiler plate code) -> Online tool (and API) provided by the Spring team to help developers bootstrap a new Spring Boot
project quickly — without manual setup.

 Boilerplate (or boilerplate code) refers to standard, reusable code or text that can be copied and used with minimal modification in
multiple places.

 It generates a ready-to-run Spring Boot project skeleton with the structure, dependencies, and configuration files already in place.

 Structure description:
◦ Project
▪ Maven
 uses [Link]
 dependency management via XML
▪ Gradle – Groovy
 uses [Link] (Groovy DSL)
 faster builds than Maven
▪ Gradle – Kotlin
 uses [Link]
 type-safe build scripts
◦ Language
▪ Java (standard choice)
▪ Kotlin
▪ Groovy (mostly used in testing)
◦ Spring Boot version
▪ 3.5.7 (✅ Stable – Recommended)
▪ SNAPSHOT → Development version
▪ RC → Release Candidate (testing phase)
▪ ❌ Never use SNAPSHOT in production
▪ ✅ Always choose latest stable
◦ Project Metadata
▪ Group
 Acts like company / organization name
 Base for package structure
 eg.,[Link] , [Link]
▪ Artifact
 Jar/War file name
 Also project folder name
 eg., [Link]
▪ Name
 Application display name
 Usually same as artifact
▪ Description
 Only for documentation
 No runtime impact
▪ Package name
 Base Java package
 All classes go under this
 eg.,[Link] , [Link]
▪ Packaging (JAR by default)
 JAR (Java ARchive): Packages a standalone Java application (desktop, CLI, or microservice). Use case:
Microservice/REST API, Cloud-native deployment (Docker, Kubernetes)
 WAR (Web Application ARchive): Packages a web application (servlets, JSP, [Link]).
▪ Configuration
 Properties ([Link]=8081)
 YAML (server: port: 8081)
▪ Java (choose version)
◦ Select dependencies (like Web, JPA, Security, etc.)
▪ In a Java/Spring Boot project, these dependencies provide pre-built features — like web servers, databases, logging, or
security — so you don’t have to code everything from scratch.
 Want to build REST APIs? ➜ spring-boot-starter-web
 Need to connect to a database? ➜ spring-boot-starter-data-jpa
 Download a ZIP file with pre-configured project structure

 How to open zip file in IntelliJ


◦ Open IntelliJ Idea ➜ Projects ➜ Open ➜ Downloads ➜ Select zip file

 PROJECT STRUCTURE

 [Link] → main entry point (@SpringBootApplication)

 test → testing is considered very important in Spring Boot. The test folder is a mirror image of your main code, containing all your
unit and integration tests, resources, and configurations for testing.

 [Link] or [Link] → manages dependencies


◦ [Link] → Java version can be changed <properties><java-version>21</java-version></properties>
(To verify the jdk version, type Ctrl+; then in SDK – select version.)

 [Link] → configuration

 TO RUN SPRING APPLICATION


Simply go to main file (stored inside src folder) → Run the application, clicking on Green Arrow Indicator → In console, you will find Tomcat
started at port 8080 → Apke 8080 port par, Tomcat server ko listen karana start kar diya hai → local network par usne 8080 port par jo bhi
request aayega, use Spring Boot Application listen karega → [Link]

 INTERNAL WORKING OF SPRING BOOT


(Bean, Dependency Injection, IOC Container, Application Context, Componenets Scanning, AutoConfiguration)

Bean

 A Bean is simply an object that is managed by the Spring IoC (Inversion of Control) container. You don’t manually create it using new;
Spring does it for you.

 Any Java object that Spring creates, configures, and manages for you is called a Spring Bean.

 Spring is responsible for:


◦ Creating the object (instantiation)
◦ Injecting its dependencies (Dependency Injection)
◦ Managing its lifecycle (initialization → usage → destruction)

Dependency Injection

 giving an object its dependencies (objects it needs) from outside — instead of creating them itself.

 There are 3 common types of DI in Spring:


◦ Constructor Depencdency Injection
▪ Inject dependency or provide dependency via constructor
▪ Spring creates the dependent Bean and injects it when constructing another Bean.
▪ It’s one of the cleanest and safest ways to create and wire Beans together.

▪ Now, we put @Component above class. @Component tells Spring to make this class a Bean.
RazorpayPaymentService → a service class that handles payments.
InternalWorkingOfSpringBootApplication → our main class that depends on RazorpayPayment

@Component registers this class as a Spring Bean.


When Spring Boot starts, it automatically creates an object of this class and keeps it in the IoC container.
Constructor injection = tells Spring what your class depends on.

 Spring Boot starts → creates the ApplicationContext (IoC Container).


 Scans your package ([Link]) for classes annotated with @Component, @Service, @Repository, etc.
 Finds RazorpayPaymentService → creates an object and stores it in the container.
 Finds InternalWorkingOfSpringBootApplication → sees it has a constructor that requires RazorpayPayment.
 Spring automatically injects the RazorpayPaymentService Bean into it.

Example Code

2. Field
Injection
























Inject dedpendency directly to a field.
 You let Spring directly inject the dependency into a field (variable) of your class using the @Autowired annotation — without using
a constructor or setter.

 How it works?
◦ Spring Boot starts → creates the ApplicationContext.
◦ It finds @Component classes: RazorpayPaymentService
◦ Creates Bean of RazorpayPaymentService.
◦ Finds @Autowired field inside InternalWorkingOfSpringBootApplication.
◦ Injects the already-created RazorpayPaymentService Bean into that field.

Example

StripePaymentService implements a PaymentService interface, and it’s doing business logic (processing a payment) — so the correct
stereotype here would be using @Service here (instead of @Controller)

@Service → for business logic classes like StripePaymentService


@Controller → for MVC controllers that handle HTTP requests
@RestController → for REST APIs (return JSON)
@Repository → for database operations
@Component → general-purpose Bean (superclass of all stereotypes)
You can use any of the above anotations in order to create Spring Beans.
Dependency Injection

Example
Here, we are facing ambiguity issue, because Spring sees two Beans that implement PaymentService: RazorpayPaymentService and
StripePaymentService.

Solution: If we remove @Component (or @Service) from one class, only the remaining annotated class will be treated as a Bean..

Now Spring finds only one Bean → StripePaymentService.

@ConditionalOnProperty

 Is a Spring Boot conditional annotation used to enable or disable a bean based on a property value in the application configuration
file (like [Link] or [Link]).

 It allows Spring to decide whether to create a bean depending on a property’s value.

Mentioned stripe payment service to be used.

@Component → Makes this class a Spring-managed bean.


@ConditionalOnProperty(...) → Tells Spring: Only register this bean if the property [Link] in the configuration file equals razorpay
Related Conditional Annotations
@ConditionalOnMissingBean → Load bean only if another bean is not present.
@ConditionalOnClass → Load bean if a class is present in the classpath.
@ConditionalOnExpression → Load bean if expression evaluates to true.
@ConditionalOnProperty → Load bean if a property matches a value.
@ConditionalOnResource → Load bean if specified resource present.

When you set debug=true, Spring Boot prints auto-configuration reports and condition evaluation logs to the console while starting the
application.
It helps you see:
 Which beans are being created ✅
 Which beans are not created ❌ (and why)
 Which @ConditionalOnProperty conditions matched or did not match

While running the app with the following code, you’ll see logs.

INTERNAL WORKING OF SPRING BOOT

1. In POJO Classes, these are your Java classes that perform specific logic – StripePaymentService and RazorpayPaymentService. Each class is
typically annotated with @Component, @ConditionalOnProperty(…), so they can become beans depending on configuration.
2. Component Scanning: Spring Boot automatically scans packages (using @ComponentScan or the default package of your main class). It
detects classes annotated with @Component, @Service, @Repository, @Controller, etc.
When detected, they become eligible beans for the IoC container (Inversion of Control Container).
3. IoC Container is the core of Spring. It is responsible for: creating beans, managing their lifecycles, and injecting dependencies (via
constructor, setter, or field injection.)

IOC Container

Application Context

Component Scanning

AutoConfiguration

What happens when you run a Spring Boot Application


Spring AOP (Aspect-Oriented Programming)

pointcut: A pointcut is an expression that matches one or more join points. Defines which methods or classes your advice should apply to.
A join point is a specific point in your program’s execution — for example: A method being called, An exception being thrown, Or a
constructor being executed.
16 November
execute
executeUpdate
executeQuery

ResultSSet

Spring Annotations
- ResponseHandler

You might also like