Java
Java
This module covers Java Fundamentals, Control Flow Statements, Methods, and Arrays.
1. Java Fundamentals
Java uses a write-once, run-anywhere (WORA) model, powered by three core components:
JVM (Java Virtual Machine): An abstract machine that executes compiled Java bytecode. It is
platform-dependent (different JVMs exist for Windows, macOS, Linux) but enables platform
independence for the application bytecode.
JRE (Java Runtime Environment): Package that bundles the JVM, core class libraries, and
supporting files. It is sufficient for running Java applications but does not contain development tools
like compilers.
JDK (Java Development Kit): A full-featured software development kit containing the JRE,
compiler ( javac ), archiver ( jar ), debugger ( jdb ), and other development utilities.
+--------------------------------------------------------+
| JDK (Development) |
| +----------------------------------------------+ |
| | JRE (Execution) | |
| | +------------------+ +-----------------+ | |
| | | JVM (Engine) | | Library Classes | | |
| | +------------------+ +-----------------+ | |
| +----------------------------------------------+ |
| Development Tools (javac, jar, javadoc, etc.) |
+--------------------------------------------------------+
2. Compilation: The Java compiler ( javac ) compiles source code into intermediate bytecode saved
in .class files (e.g., [Link] ).
3. Execution: The JVM's ClassLoader loads the .class files, the Bytecode Verifier checks for safety,
and the Execution Engine (Interpreter + Just-In-Time [JIT] Compiler) translates bytecode to machine
code.
[[Link]] --(javac [Link])--> [[Link] (Bytecode)] --(java App)--> [JVM
ClassLoader] --> [Execution Engine] --> [Machine Code]
Every Java program must have at least one class definition. The entry point of execution is the main
method.
public : Access modifier making the method accessible from outside the class (specifically by the
JVM).
static : Allows the JVM to call the method without instantiating the class.
void : Return type indicating the method does not return any value.
main : The name of the method recognized by the JVM as the entry point.
Variables
A variable is a container that holds data during execution. In Java, variables must be declared with a
data type.
Local Variables: Declared inside a method, constructor, or block. Must be initialized before use;
they do not have default values.
Instance (Object) Variables: Declared inside a class but outside methods. Initialized automatically
to defaults ( 0 , null , false ).
Static (Class) Variables: Declared with the static keyword inside a class. Shared across all
instances of that class.
Data Types
Java is a statically-typed language. Types are divided into two main categories:
Data Types
/ \
Primitive Types Non-Primitive Types (References)
/ \ |
Numeric Non-Numeric +-- String, Arrays, Classes,
/ \ | Interfaces, Enums
Integer Floating-Point char, boolean
(byte, (float, double)
short,
int, long)
Primitives are stored directly on the stack and represent single values:
Size Default
Type Range
(Bytes) Value
long 8 0L
−263 to 263 − 1 (suffix L required:
10000000000L )
Refer to objects or arrays. They store the memory address of the actual object (allocated on the heap).
Examples include classes, arrays, interfaces, and strings.
Type Casting
Happens automatically when converting a smaller type size to a larger type size. No data loss occurs.
int myInt = 9;
double myDouble = myInt; // Implicit casting: 9.0
Must be done manually by placing the type in parentheses in front of the value. Can result in data loss
or truncation.
Operators
& , | , ^ , ~ , << ,
Bitwise Bitwise operations and binary bit-shifting.
>> , >>>
= , += , -= , *= ,
Assignment Assigns and modifies variables.
/= , %=
Input/Output
Easy to parse primitives and lines using regex. Slow because of parser overhead. Not thread-safe.
import [Link];
Scanner sc = new Scanner([Link]);
int age = [Link]();
String name = [Link](); // or nextLine()
Reads character streams with buffering. Fast read speeds (recommended for competitive
programming/DSA). Needs explicit exception handling ( IOException ).
import [Link];
import [Link];
import [Link];
Keywords: Reserved words with specific meanings in Java (e.g., class , public , new , this ).
They cannot be used as identifiers.
Identifiers: Names given to classes, methods, and variables. Must start with a letter, $ , or _ .
Case-sensitive. Cannot contain spaces or match reserved keywords.
Decision Making
1. if , if-else , Nested if , and else-if Ladder
Selects one of many code blocks to execute based on an expression ( byte , short , char , int ,
String , or enum ).
int day = 3;
switch (day) {
case 1: [Link]("Monday"); break;
case 2: [Link]("Tuesday"); break;
case 3: [Link]("Wednesday"); break; // Matches
default: [Link]("Weekend");
}
[!WARNING]
Forgetting a break statement causes code execution to "fall through" into subsequent cases,
executing them regardless of whether they match.
Uses the arrow ( -> ) syntax. Eliminates fall-through (no break needed) and can return values directly.
String status = switch (errorCode) {
case 404 -> "Not Found";
case 500, 503 -> "Server Error";
default -> {
[Link]("Logging unknown error...");
yield "Unknown Error"; // 'yield' is used in multi-line switch blocks to
return a value
};
};
Loops
// 3. do-while loop: body executed at least once, condition checked at the end
int x = 10;
do {
[Link]("Runs once");
x++;
} while (x < 10);
Jump Statements
continue : Skips the current iteration of the loop and proceeds to the next iteration.
return : Terminates the execution of a method and optionally returns a value to the caller.
3. Methods
A method is a block of code containing statements that runs only when called.
Method Overloading
Declaring multiple methods in the same class with the same name but different parameter lists. It is
compile-time polymorphism.
Rules for overloading:
[!IMPORTANT]
Changing the return type alone or the access modifier alone is not valid method overloading
and will trigger a compile-time error.
Allows a method to accept zero or more arguments of a specified type. Represented by three dots
( ... ).
[!WARNING]
A method can have only one varargs parameter, and it must be the last parameter in the
signature (e.g., public void printInfo(String label, int... nums) ).
For Primitives: A copy of the value is passed. Modifying the parameter inside the method does not
affect the original variable.
For Objects: A copy of the reference (memory address) is passed. The reference copy points to the
same object on the heap. Thus:
Modifying fields of the object inside the method will affect the caller's object.
Reassigning the reference variable inside the method to a new object will not change the caller's
reference.
Recursion
A process in which a method calls itself. Requires a base case to terminate recursion, otherwise it
triggers a StackOverflowError due to exhaustively consuming call stack memory frames.
4. Arrays
An array is a fixed-size, homogeneous container that holds elements of the same data type.
1D Arrays
Jagged Arrays
An array of arrays where the member arrays can have different sizes.
Array Traversal
Linear Search
Binary Search
Finds target in a sorted array by repeatedly dividing the search space in half. O(log N ) time
complexity.
[Link](arr) : Sorts the array into ascending order (uses Dual-Pivot Quicksort for primitives,
Timsort for objects). Time complexity: O(N log N ).
[Link](arr, key) : Searches sorted array for key . Returns index if found, else
negative insertion point reference.
Object-Oriented Programming is a paradigm centered around objects rather than actions, and data
rather than logic. It enables modularity, reusability, and scalability.
// Methods (Behavior)
void accelerate() {
speed += 10;
}
}
2. Constructors
Types of Constructors
1. Default Constructor
If no constructor is defined in a class, the Java compiler automatically inserts a public default
constructor with no arguments. It initializes instance variables to their default values.
[!WARNING]
If you write any custom constructor (parameterized or no-arg), the compiler does not generate
the default constructor automatically. You must define it manually if you still need it.
2. Parameterized Constructor
// Parameterized constructor
public Student(String name, int age) {
[Link] = name;
[Link] = age;
}
}
Constructor Overloading
Having multiple constructors with different parameter lists (type, count, or sequence) in the same class.
Constructor Chaining
The process of calling one constructor from another constructor in the same class (using this() ) or
from the parent class (using super() ).
[!IMPORTANT]
The call to this() or super() must be the very first statement in the constructor. You cannot
use both in the same constructor.
// Constructor 1 (Chained)
public Device() {
this("Generic"); // Calls Constructor 2
}
// Constructor 2 (Chained)
public Device(String type) {
this(type, 0); // Calls Constructor 3
}
3. Encapsulation
Encapsulation is the practice of bundling data (variables) and code (methods) together into a single unit
(class) and restricting direct access to some components (data hiding).
Expose: Provide public getter and setter methods to inspect and modify values. This allows
verification and write-protection logic to execute before data modifications occur.
4. Inheritance
The mechanism by which one class acquires the properties and behaviors of another class using the
extends keyword. It facilitates code reusability and creates an "IS-A" relationship.
Multilevel: A class inherits from a parent, which itself inherits from another parent class (e.g., C
extends B, B extends A).
Hierarchical: Multiple child classes inherit from a single parent class.
[!CAUTION]
Multiple Inheritance is NOT supported in Java using classes. A class cannot extend more
than one class (e.g., class C extends A, B is illegal). This avoids the Diamond Problem
(ambiguity in which method implementation to inherit from A and B).
5. Polymorphism
Polymorphism
/ \
Compile-Time Run-Time
(Overloading) (Overriding)
Resolved during compilation. Achieved via Method Overloading (same method name, different
signatures in the same class).
Resolved during execution. Achieved via Method Overriding (subclass provides a specific
implementation of a method declared in its parent class).
2. The return type must be the same or a covariant return type (a subclass of the parent's return
type).
3. The access modifier cannot be more restrictive than the parent's (e.g., a protected method cannot
be overridden as private ).
6. Abstraction
Abstraction is the process of hiding implementation details and showing only key features to the user. It
is achieved using Abstract Classes and Interfaces.
1. Abstract Classes
Can have both abstract methods (no body) and concrete methods (with body).
2. Interfaces
An interface is a blueprint of a class that contains static constants and abstract methods (before Java
8). It represents a contract and enables Multiple Inheritance and loose coupling.
Interface Rules:
A class can implement multiple interfaces (e.g., class A implements Interface1, Interface2 ).
Default Methods: Methods with bodies using the default keyword to allow interface evolution
without breaking implementation classes.
Private Methods (Java 9+): Used to share code between default methods.
interface Flyable {
void fly(); // implicitly public abstract
Can have abstract, concrete, Can have abstract, default (Java 8),
Methods
static, final methods. static, and private methods.
Association
/ \
Aggregation Composition
(Weak HAS-A) (Strong HAS-A)
Example: A Department has a Teacher . If the department is closed, the teachers still exist.
class Department {
private List<Teacher> teachers; // Reference to teachers
Department(List<Teacher> teachers) {
[Link] = teachers;
}
}
Example: A House has a Room . If the house is demolished, the room is destroyed.
class House {
private Room studyRoom; // Room created and destroyed with House
House() {
[Link] = new Room("Study");
}
}
03_Advanced_OOP_and_Packages
This module covers keywords, package scopes, access level security, and Java String handling.
super is a reference variable used to refer to the immediate parent class object.
Access Parent Variables: Resolve shadowing when parent and child share field names.
Invoke Parent Constructors: Call parent constructors using super() (must be the first statement
of the child constructor).
class Parent {
void show() { [Link]("Parent Show"); }
}
class Child extends Parent {
void show() {
[Link](); // Calls parent's show method
[Link]("Child Show");
}
}
Applied
Behavior Example
To
Used for memory management. Members marked static belong to the class itself rather than
instances.
Static Variables: Shared single copy among all instances of the class. Initialized when the class is
loaded.
Static Methods: Can be invoked without creating an instance. Can only access static variables and
call static methods directly (cannot use this or super ).
Static Blocks: Executed once when the class is loaded into JVM memory. Used to initialize static
variables.
Static Nested Classes: Nested classes that do not require an outer class instance reference.
The root class of the Java hierarchy. Every class implicitly inherits from [Link] .
Crucial inherited methods:
String toString() : Returns string representation of object (defaults to ClassName@hashCode ).
boolean equals(Object obj) : Checks references equality by default. Often overridden for value
comparison.
int hashCode() : Returns integer hash representation. Must be overridden if equals() is
overridden.
Object clone() : Creates copy of object (requires implementing Cloneable interface).
Dynamic Method Dispatch: The mechanism by which a call to an overridden method is resolved at
runtime (rather than compile-time). This is the foundation of runtime polymorphism.
An overriding method in a subclass can declare a return type that is a subclass (derived type) of the
return type declared in the parent method.
class Producer {
Producer get() { return this; }
}
class SubProducer extends Producer {
@Override
SubProducer get() { return this; } // Covariant return type (SubProducer
instead of Producer)
}
2. Packages
Packages group related classes, interfaces, and subpackages. They resolve naming conflicts and
control directory structures.
Built-in Packages: Bundled with JDK (e.g., [Link] [implicitly imported], [Link] , [Link] ,
[Link] ).
User-defined Packages: Declared via the package statement at the top of the file:
package [Link];
Importing:
import [Link].*; - Wildcard import (imports all public classes in package; does not
import subpackages).
import static [Link].*; - Static import (allows calling static fields/methods directly
without class name).
3. Access Modifiers
Java provides access control levels to restrict visibility of classes, constructors, variables, and methods.
private Yes No No No
default (no
Yes Yes No No
modifier)
4. Strings in Java
Once created, a String object's content cannot be changed. Modification creates a new String
object.
String Pool (Space Efficiency): Reuses string literals, saving Heap space.
Security: Databases, usernames, and file paths are passed as strings. Immutability prevents values
from changing mid-execution.
Hashcode Caching: The hashcode is computed once and cached, making Strings fast keys for
HashMap .
When creating strings using Literals ( String s = "Java" ), Java checks the pool first. If it exists,
the existing reference is shared.
When using the new Keyword ( String s = new String("Java") ), Java bypasses the pool and
allocates a new object in the normal Heap.
Heap Memory
+-----------------------------------------+
| [String Object] (Normal Heap) |
| Ref: s2 --------------------+ |
| | |
| +--------------------------+ | |
| | String Pool | | |
| | | | |
| | "Java" <----+ s1 | | |
| | <----+ intern() | | |
| +--------------------------+ | |
+-----------------------------------------+
StringBuilder vs StringBuffer
When extensive string manipulations (concatenations, inserts, deletes) are required, using String is
inefficient due to object recreation. Use mutable alternatives instead:
== Operator: Compares reference equality (checks if both variables point to the exact same
memory address).
intern() Method: Invoked on a String object. If the string is already in the String Pool, its
reference is returned. If not, the string is added to the pool and the pool reference is returned.
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
String s4 = [Link](); // Fetch pool reference
This module covers Java Exception safety, Type encapsulation using wrappers, and compile-time type-
safety with Generics.
1. Exception Handling
An exception is an unwanted or unexpected event that occurs during the execution of a program (at
runtime) that disrupts the normal flow of instruction execution.
Exception Hierarchy
All exception and error types are subclasses of the Throwable class, which is the root of the hierarchy.
Throwable
/ \
Exception Error
/ \ \
(Checked) RuntimeException (StackOverflowError,
(Unchecked) OutOfMemoryError, etc.)
Error : Indicates serious, non-recoverable problems that a reasonable application should not try to
catch (e.g., OutOfMemoryError , StackOverflowError , VirtualMachineError ).
Checked Exceptions: Classes that extend Exception but do not inherit from
RuntimeException . They are checked at compile-time. The program must handle them or
declare them, otherwise the code won't compile (e.g., IOException , SQLException ,
FileNotFoundException ).
try : Wraps a block of code where an exception might occur. Must be followed by at least one
catch block or a finally block.
catch : Used to handle exceptions thrown in the associated try block. Multiple catch blocks are
evaluated sequentially from specific to general.
Multi-catch (Java 7+): Catch multiple unrelated exceptions in a single block using | .
catch (ArithmeticException | NullPointerException e) { ... }
finally : Executed regardless of whether an exception is thrown, caught, or if the block returns
early. Ideal for resource cleanup (closing connections, files).
Exceptions: finally will not execute if [Link]() is invoked, if the JVM crashes, or
during infinite loops.
throw : Used to explicitly throw a single instance of an exception (e.g., throw new
ArithmeticException("Divide by zero"); ).
throws : Used in a method signature to declare that the method may propagate specific checked
exceptions to its caller.
Wrapper classes provide a way to use primitive data types as objects. They are located in the
[Link] package.
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
Autoboxing: The automatic conversion that the Java compiler makes between the primitive types
and their corresponding object wrapper classes (e.g., converting an int to an Integer ).
Unboxing: The automatic conversion of wrapper class objects back to their corresponding primitive
values (e.g., converting an Integer to an int ).
// Autoboxing
Integer obj = 100; // Compiler runs: [Link](100)
// Unboxing
int primitive = obj; // Compiler runs: [Link]()
3. Generics
Generics add type safety to Java. They allow classes, interfaces, and methods to take types as
parameters, enabling code reuse with strict compile-time checking (eliminating runtime
ClassCastException hazards).
// Generic Class
public class Box<T> { // T is a type parameter
private T value;
public void set(T value) { [Link] = value; }
public T get() { return value; }
}
// Generic Method
public static <E> void printArray(E[] elements) {
for (E element : elements) {
[Link](element + " ");
}
[Link]();
}
Limits the types that can be passed to a type parameter. Use extends for upper bounding.
public class NumericBox<T extends Number> { // Accepts Integer, Double, Float, etc.
private T value;
public double doubleValue() {
return [Link]();
}
}
Wildcards ( ? )
1. Unbounded Wildcard ( ? ): Represents any type. Useful when a method uses only functionality
found in the Object class.
2. Upper Bounded Wildcard ( ? extends T ): Restricts the unknown type to be a specific type T or its
subclasses. Represents covariance. Useful for reading from a structure.
3. Lower Bounded Wildcard ( ? super T ): Restricts the unknown type to be a specific type T or its
superclasses. Represents contravariance. Useful for writing to a structure.
Producer ( extends ): If you are reading data from a collection, it acts as a producer. Use ? extends
T.
Consumer ( super ): If you are writing data into a collection, it acts as a consumer. Use ? super T .
Type Erasure
Java implements generics using type erasure to ensure backward compatibility with older Java versions
that did not support generics.
During compilation, the compiler replaces all type parameters in generic types with their bounds (or
Object if unbounded).
The Java Collections Framework (JCF) is a unified architecture for representing and manipulating
collections of data.
Iterable
|
Collection
/ | \
List Queue Set
| | |
ArrayList Priority- HashSet
LinkedList Queue LinkedHashSet
Vector | |
Stack Deque TreeSet
|
ArrayDeque
2. List Interface
An ordered collection (sequence) that allows duplicate elements and positional access.
ArrayList :
LinkedList :
Underlying Structure: Doubly linked list.
Features: Implements both List and Deque . Fast insertions/deletions at endpoints (O(1)) but
slow search/random access (O(N )) because it must traverse node by node. High memory
overhead due to pointer storage.
Vector (Legacy):
Dynamic array similar to ArrayList but thread-safe (methods are synchronized). Slower than
ArrayList due to locking overhead.
Stack (Legacy):
PriorityQueue :
Features: Elements are ordered based on natural ordering or a custom Comparator . Head of
the queue is always the smallest element. Does not allow null elements. O(log N ) for
insertion and extraction.
Features: Elements can be added/removed from both ends. Faster than Stack (when used as
a stack) and LinkedList (when used as a queue). Does not allow null .
4. Set Interface
HashSet :
Features: Unordered and unsorted. Allows at most one null element. O(1) average time
complexity for basic operations ( add , remove , contains ).
LinkedHashSet :
Underlying Structure: Hash table with a doubly-linked list running through its elements.
Features: Maintains insertion order. Slightly slower than HashSet due to maintaining the
linked list.
TreeSet :
Features: Elements are stored in a sorted order (natural order or custom Comparator ). Does
not allow null . Time complexity for basic operations is O(log N ).
5. Map Interface
An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most
one value.
HashMap :
Underlying Structure: Hash table (array of buckets containing Linked Lists/Red-Black Trees).
Features: Unordered and unsorted. Allows one null key and multiple null values. O(1)
average performance for insertions and retrieval.
LinkedHashMap :
Extends HashMap . Maintains insertion order (or access-order) using a doubly-linked list.
TreeMap :
Implements NavigableMap (backed by a Red-Black Tree). Keys are stored in sorted order.
Does not allow null keys. O(log N ) time complexity for lookup/insertion.
Hashtable (Legacy):
Synchronized (thread-safe) version of HashMap . Does not allow any null key or value.
A HashMap consists of an array of Node objects (called buckets). Each node contains:
2. K key
3. V value
Key Operations
1. How put(key, value) works:
1. Hash Calculation: Calls the key's hashCode() and applies an internal defensive hash function to
spread bits.
2. Index Calculation: Calculates the index bucket using index = hash & (n - 1) (where n is the
array length, always a power of 2).
3. Collision Handling:
If the bucket is empty, a new Node is created and inserted at the index.
If the key already exists (checked via hashCode() and equals() ), the old value is
overwritten.
4. Treeification: If a bucket's linked list size exceeds 8 and the total HashMap capacity is at least 64,
the linked list is converted into a Red-Black Tree to improve search time from O(N ) to O(log N ).
If size falls below 6 during resizing, it is converted back to a linked list.
5. Resize check: If size exceeds the threshold (Capacity × Load Factor [default = 0.75]), the map
doubles its capacity and rehashes all elements.
2. Goes to the bucket array index and compares the key in the first node using equals() .
4. If not, traverses the Linked List or Red-Black Tree calling equals() on each node.
7. Iterators
Iterator vs ListIterator
Read-only traversal,
Operations Supports read, remove() , set() , add()
supports remove()
Comparable
Implemented by the class itself to define its natural ordering (e.g., sorting Students by Roll
Number).
Overrides a single method: int compareTo(T o) .
Comparator
Time
Allows Allows
Collection Ordered Sorted Complexity
Duplicates Nulls
(Search)
Yes
LinkedList
(Insertion)
No Yes Yes O(N )
Yes
HashSet No No No
(max 1)
O(1) average
Yes Yes
LinkedHashSet
(Insertion)
No No
(max 1)
O(1) average
Yes
TreeSet
(Sorted)
Yes No No O(log N )
This module covers JVM runtime memory areas, Object lifecycle tracking, Garbage Collection
mechanisms, Class Loading, and performance tuning configurations.
+-----------------------------------------------------------------------+
| JVM Memory |
| |
| [ Shared across all threads ] |
| +--------------------------+ +-------------------------------+ |
| | Heap | | Method Area | |
| | (Objects & Arrays) | | (Class Metadata/Constants) | |
| +--------------------------+ +-------------------------------+ |
| |
| [ Thread-Local (Private to each thread) ] |
| +------------------+ +------------------+ +---------------+ |
| | JVM Stack | | PC Register | | Native Stack | |
| | (Frames/Locals) | | (Current Instruct) | | (C/C++ Calls) | |
| +------------------+ +------------------+ +---------------+ |
+-----------------------------------------------------------------------+
1. Stack Memory
Content: Method execution frames. Inside a frame, it stores local variables, primitive data values,
and reference addresses pointing to objects on the Heap.
2. Heap Memory
Method Area: Stores class structure definitions, field details, method data, code for
methods/constructors, and the runtime constant pool.
PermGen (Permanent Generation): The legacy implementation of the Method Area up to Java 7. It
had a fixed maximum size, leading to frequent OutOfMemoryError: PermGen space .
Metaspace (Java 8+): Replaced PermGen. It stores class metadata but is allocated out of Native
Memory (local system RAM) rather than Java Heap. It resizes dynamically, lowering the risk of
running out of class metadata space.
1. Class Loading: JVM checks if the User class is loaded. If not, ClassLoader loads metadata into
Metaspace.
2. Heap Allocation: JVM allocates space for the User object in the Heap.
3. Initialization: Default values are set, instance blocks execute, and the User constructor runs.
4. Stack Reference: The reference variable u is stored on the calling thread's stack frame, containing
the heap memory address of the newly created object.
To control how objects are garbage collected, Java provides four reference levels in [Link] :
An object with a active strong reference is never eligible for garbage collection.
2. Soft Reference:
GC only reclaims soft-referenced objects if the JVM is running out of memory (great for building
memory-sensitive caches).
3. Weak Reference:
Reclaimed during the very next GC cycle, regardless of whether memory is full (used in
WeakHashMap ).
4. Phantom Reference:
Example: PhantomReference<User> phantom = new PhantomReference<>(u, queue);
Used to track when the object is physically removed from memory. Requires a reference queue.
Garbage Collection is the process of automatically identifying and deleting unreachable objects from the
Heap, freeing up space for new allocations.
Most objects are short-lived. To optimize collection passes, the Heap is divided into distinct generations:
+--------------------------------------------------------+-------------------+
| Young Generation | Old Generation |
| +------------------+ +---------------------------+ | (Tenured Space) |
| | Eden Space | | Survivor Spaces | | |
| | | | [ S0 ] | [ S1 ] | | |
| +------------------+ +---------------------------+ | |
+--------------------------------------------------------+-------------------+
1. Young Generation:
If objects survive multiple Minor GC runs (exceeding the aging threshold, e.g., default 15), they
are "promoted" to the Old Generation.
When the Old Generation fills up, a Major GC occurs (often causing a Stop-The-World pause).
Mark and Sweep: Traces references from GC Roots (threads, static variables, local stack refs) to
mark active objects, then sweeps unmarked objects.
Mark-Sweep-Compact: Same as above but slides all surviving objects to one side of the heap to
prevent memory fragmentation.
Copying: Splits memory in half, marks active objects, and copies them to the other half, cleanly
freeing the entire source space (used in Young Gen).
ZGC (Zero Garbage Collector): An ultra-low latency collector designed to handle massive heaps
(terabytes) with pauses not exceeding a few milliseconds.
4. JVM Internals
+---------------------------------------------+
| ClassLoader Subsystem |
| Loading ---> Linking ---> Initialize |
+---------------------------------------------+
|
+---------------------------------------------+
| Runtime Data Areas |
| Heap | Stack | Metaspace | PC | Native |
+---------------------------------------------+
|
+---------------------------------------------+
| Execution Engine |
| Interpreter | JIT Compiler | GC Engine |
+---------------------------------------------+
ClassLoader Subsystem
Loads compiled .class files into JVM memory. It operates in three phases:
1. Loading: Locates and reads .class binary data. Uses delegation pattern:
2. Linking:
Preparation: Allocates memory for static fields and assigns default values.
3. Initialization: Executes static blocks and assigns initial values to static variables.
Interpreter: Reads bytecode instructions one by one and executes them. It is fast to startup but
slower during loops and repetitive execution.
JIT (Just-In-Time) Compiler: Monitors code execution. If a block of code is executed frequently
("Hotspot"), JIT compiles that bytecode into native machine code directly executed by the CPU,
bypassing interpretation.
Includes compilers like C1 (client compiler) for fast compilation and C2 (server compiler) for
heavily optimized code.
JVM parameters are configured via command-line flags when starting the application:
-Xms<size> : Sets the initial heap size (e.g., -Xms2g for 2 Gigabytes).
-Xmx<size> : Sets the maximum heap size (e.g., -Xmx4g for 4 Gigabytes). Prevents heap
exhaustion errors.
-Xss<size> : Sets the stack size per thread (e.g., -Xss512k to fit more threads).
-XX:+UseZGC : Instructs JVM to use the Z Garbage Collector (for low latency).
-XX:NewRatio=2 : Ratio of Old Gen to Young Gen size (2 means Old Gen is twice the size of Young
Gen).
07_Multithreading_Concurrency
Multithreading is a Java feature that allows concurrent execution of two or more parts of a program for
maximum utilization of CPU.
1. Thread Creation
Java provides three primary mechanisms for defining and running concurrent threads:
Define task logic by implementing Runnable . Exposes better design practices (allows subclassing other
classes).
Similar to Runnable , but can return a value and throw checked exceptions. It returns a Future
object to inspect results.
import [Link];
import [Link];
class MyCallable implements Callable<Integer> {
public Integer call() throws Exception {
return 42; // Returns value
}
}
// Execution:
// FutureTask<Integer> task = new FutureTask<>(new MyCallable());
// new Thread(task).start();
// int result = [Link](); // Blocks until result is ready
A thread can exist in one of six states, defined by the [Link] enum:
2. RUNNABLE: Thread is running or ready to run in JVM (waiting for CPU allocation).
3. BLOCKED: Thread is waiting to acquire a monitor lock to enter a synchronized block/method.
4. WAITING: Thread is waiting indefinitely for another thread to perform a specific action (e.g.,
[Link]() , [Link]() ).
When multiple threads access shared mutable data, a Race Condition can occur, causing corrupted
data. Thread-safety prevents this.
Guarantees mutual exclusion: only one thread can execute the protected code block at a time.
Synchronized Block: Locks on a specific object monitor, allowing smaller critical sections.
Every read of a volatile variable will be read from the computer's Main Memory, not from the CPU
cache.
Every write to a volatile variable will be written to Main Memory, not just the CPU cache.
It ensures Visibility of variables across threads. It does not solve atomicity (e.g., count++ is not
thread-safe even if count is volatile).
ReentrantLock :
Features: Allows lock polling ( tryLock() ), interruptible lock waits, and fairness policies
(granting lock to longest-waiting thread).
wait() : Causes the current thread to release its monitor lock and go to sleep until another thread
wakes it up.
Managing thread creation ( new Thread() ) manually is expensive and inefficient. The Executors
Framework separates task submission from execution details.
Executor (Interface)
|
ExecutorService (Interface)
/ \
ThreadPoolExecutor ScheduledThreadPoolExecutor
Creates a pool with a fixed number of threads. Uncompleted tasks queue up in an unbounded
queue ( LinkedBlockingQueue ).
2. CachedThreadPool :
Creates a thread pool that creates new threads as needed, but will reuse previously constructed
threads when they are available.
Unused threads are terminated after 60 seconds of inactivity. Good for short-lived asynchronous
tasks.
3. SingleThreadExecutor :
Uses a single worker thread to execute tasks sequentially. Ensures execution order.
4. ScheduledThreadPool :
Uses a ForkJoinPool working stealing algorithm. Threads steal pending tasks from other
threads' queues when their own queue is empty.
This module covers the functional programming paradigm introduced in Java 8 and the rapid evolution
of the language up to LTS version 21.
1. Java 8 Features
Released in 2014, Java 8 was a massive shift that introduced functional programming constructs,
improving code conciseness and enabling parallel processing.
Lambda Expressions
Anonymous functions (no name, no return type, no modifiers) that implement functional interface
methods.
// Traditional
Runnable r1 = new Runnable() {
public void run() { [Link]("Hello"); }
};
// Lambda Expression
Runnable r2 = () -> [Link]("Hello");
Functional Interfaces
An interface that contains exactly one abstract method (SAM). Can contain any number of default and
static methods. Marked with @FunctionalInterface .
Method: boolean test(T t) (e.g., check if a number is even: num -> num % 2 == 0 ).
Method References
A shorthand syntax for Lambdas that call an existing method. Uses the double-colon operator ( :: ).
2. Stream API
A Stream is a sequence of elements supporting sequential and parallel aggregate operations. It does
not store elements (not a data structure); it conveys elements from a source (collection, array) through a
pipeline of operations.
These operations return a new Stream and are not executed until a terminal operation is invoked.
These operations produce a final non-stream result (value, collection, side effect) and close the stream.
reduce(BinaryOperator) : Combines elements to produce a single value (e.g., sum, min, max).
3. Optional Class
A container object which may or may not contain a non-null value. It is designed to prevent
NullPointerException (NPE) and clean up null-checking clutter.
// Checking presence
if ([Link]()) {
[Link]([Link]());
}
// Fluent handling
String name = [Link]("Default Name"); // Fallback value
String uppercaseName = [Link](String::toUpperCase).orElseThrow(() -> new
RuntimeException("Empty"));
The old [Link] and Calendar classes were thread-unsafe, mutable, and hard to read. Java 8
introduced the thread-safe, immutable [Link] package:
Enables type inference for local variables. The compiler infers the type, keeping runtime safety identical.
Cannot be used for instance variables, method parameters, or return types.
Concise data carrier classes that automatically generate standard boilerplates: immutable fields,
getters, equals() , hashCode() , toString() , and a constructor.
Must use the sealed keyword and list permitted subclasses using permits .
Multi-line string literals that avoid escape sequences and align indentation automatically.
Project Loom introduces lightweight, user-space virtual threads that run on top of carrier threads.
Traditional thread: 1 : 1 mapping to OS kernel thread (expensive, max out around thousands).
Virtual thread: M : N mapping. JVM multiplexes millions of virtual threads on a small pool of carrier
kernel threads.
Controls access explicitly: a module must require other modules and export its own packages to
expose classes.
module [Link] {
requires [Link];
exports [Link];
}
09_IO_File_JDBC_Networking
This module covers stream communication, file persistence, database connectivity, and socket-based
network programming.
Stream
/ \
Byte Stream Character Stream
(8-bit bytes) (16-bit Unicode)
/ \ / \
InputStream OutputStream Reader Writer
Used to read and write 8-bit bytes of binary data (images, audio, videos, files).
Used to read and write 16-bit Unicode characters. Automatically handles character encoding
translations.
Wraps raw streams to read or write data in memory buffer blocks rather than invoking single-byte/char
disk calls, drastically reducing overhead.
Serialization: The process of converting an object's state into a byte stream, allowing it to be saved
to a file or sent over a network.
Deserialization: The reverse process of recreating the Java object from the byte stream.
Serializable Interface: A marker interface (no methods) that a class must implement to enable
serialization.
transient Keyword: Applied to variables to exclude them from serialization (e.g., passwords,
temporary cached states).
import [Link];
String name;
transient String password; // Excluded from serialization
}
2. File Handling
Java offers the legacy [Link] API and the modern [Link] (New I/O) API (Java 7+):
Legacy [Link]
Offers non-blocking operations, symbol link support, and utility classes ( Path , Paths , Files ).
import [Link];
import [Link];
import [Link];
// File deletion
[Link](path);
JDBC is a Java API that manages database connections and executes SQL statements.
+-----------------+
| Java Application|
+-----------------+
|
+-----------------+
| JDBC API |
+-----------------+
|
+-----------------+
| Driver Manager |
+-----------------+
|
+-----------------+
| JDBC Driver |
+-----------------+
|
+-----------------+
| Database |
+-----------------+
Core Components
Statement : Used to run static SQL statements. Susceptible to SQL Injection attacks because
parameters are concatenated into raw strings.
PreparedStatement : Compiles the SQL query first. Uses placeholder parameters ( ? ). Prevents
SQL Injection, improves performance due to pre-compilation, and is clean.
ResultSet : A cursor representing a database result set table. Iterated using .next() .
import [Link].*;
// Querying
try (Statement stmt = [Link]();
ResultSet rs = [Link]("SELECT * FROM users")) {
while ([Link]()) {
[Link]("User ID: " + [Link]("id") + ", Username:
" + [Link]("username"));
}
}
} catch (SQLException e) {
[Link]();
}
}
}
4. Networking
Networking in Java relies on socket connections in the [Link] package.
Sockets
Uses ServerSocket (for server) and Socket (for clients). Communicates via I/O streams.
[Link]("Hello Server!");
[Link]("Server responded: " + [Link]());
}
}
}
This module covers Runtime Reflection, Custom Meta-programming annotations, core Software Design
Patterns, and Java-specific implementations of major Data Structures and Algorithms.
1. Reflection API
Reflection is an API that allows inspecting and modifying the runtime behavior of applications. You can
inspect classes, interfaces, fields, methods, and constructors at runtime, even if they are declared
private .
Key Classes
import [Link].*;
// Reading value
String keyVal = (String) [Link](personInstance);
[Link]("Read private field: " + keyVal);
// Modifying value
[Link](personInstance, "NEW_SECRET_KEY");
}
}
2. Annotations
Annotations are metadata added to code that do not change execution directly but can be read by
compiler tools, runtime reflection, or build configurations.
@Override : Instructs compiler that the annotated method overrides a parent method.
Custom annotations are declared using @interface . Meta-annotations configure their behavior:
@Target : Defines where annotation can be applied (e.g., [Link] , FIELD , TYPE ).
import [Link].*;
3. Design Patterns
Design patterns are reusable, templated solutions to common software design problems.
Factory Pattern
Decouples object instantiation logic by letting subclasses choose which class to instantiate.
class NotificationFactory {
public static Notification createNotification(String channel) {
return switch (channel) {
case "EMAIL" -> new EmailNotification();
case "SMS" -> new SmsNotification();
default -> throw new IllegalArgumentException("Unknown channel");
};
}
}
Builder Pattern
Observer: Subject maintains list of dependents (observers) and notifies them automatically of state
changes (e.g. event listeners).
class ShoppingCart {
void checkout(int total, PaymentStrategy payment) { [Link](total); }
}
import [Link].*;
[Link](arr, l, L, 0, n1);
[Link](arr, m + 1, R, 0, n2);
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) arr[k++] = L[i++];
else arr[k++] = R[j++];
}
while (i < n1) arr[k++] = L[i++];
while (j < n2) arr[k++] = R[j++];
}
}