Java Complete Guide →
History of Java
The Birth of Java
Java was created by James Gosling at Sun Microsystems (now owned by Oracle) in 1995. Originally called "Oak", it was renamed to Java after the Java coffee.
Why Was Java Created?
In the early 1990s, developers faced major challenges:
- Platform dependency - Code written for Windows wouldn't work on Mac or Unix
- Memory management issues - Languages like C/C++ required manual memory management
- Pointer complexity - Pointers in C/C++ caused crashes and security vulnerabilities
- No internet support - Existing languages weren't designed for networked applications
The Original Goal
Java was initially developed for interactive television and embedded systems like set-top boxes. The project was called "Green Project".
However, the technology was too advanced for the digital cable television industry at that time. When the World Wide Web exploded in popularity, Sun Microsystems realized Java was perfect for internet programming.
Key Principles (WORA)
"Write Once, Run Anywhere" (WORA)
This became Java's revolutionary promise - code compiled on one platform could run on any other platform without modification.
Java's Evolution
| Version | Year | Major Features |
|---|---|---|
| Java 1.0 | 1996 | First stable version |
| Java 5 | 2004 | Generics, Annotations, Enums |
| Java 8 | 2014 | Lambda expressions, Stream API |
| Java 11 | 2018 | LTS version, HTTP Client |
| Java 17 | 2021 | LTS version, Sealed classes |
| Java 21 | 2023 | LTS version, Virtual Threads |
Why Java Became Popular
- Platform Independence - True WORA capability
- Object-Oriented - Clean, modular code organization
- Automatic Memory Management - Garbage collection handled by JVM
- Rich API - Extensive standard library
- Security - Built-in security features
- Multithreading - Native support for concurrent programming
- Community - Massive developer ecosystem
Java Today
Java remains one of the most popular programming languages, powering:
- Enterprise applications (banking, finance)
- Android mobile applications
- Big data technologies (Hadoop, Spark)
- Cloud applications (AWS, Azure, Google Cloud)
- IoT devices
- Scientific applications
Java Internal Working (JDK, JRE, JVM)
Understanding JDK, JRE, and JVM
The Java Ecosystem Hierarchy
JVM (Java Virtual Machine)
The JVM is an abstract machine that executes Java bytecode.
What it does:
- Loads bytecode (.class files)
- Verifies bytecode for security
- Executes bytecode
- Provides runtime environment
- Manages memory (heap, stack)
- Performs garbage collection
Platform Independence: JVM is platform-dependent, but Java bytecode is platform-independent. This is why you need different JVMs for Windows, Mac, and Linux, but the same .class file runs on all of them.
JVM Components
- Class Loader - Loads .class files into memory
- Bytecode Verifier - Checks code for security violations
- Execution Engine - Executes bytecode (interpreter + JIT compiler)
- Runtime Data Areas - Method area, heap, stack, PC registers, native method stacks
- Garbage Collector - Automatic memory management
JRE (Java Runtime Environment)
The JRE provides the environment to run Java applications.
Contains:
- JVM
- Java Class Libraries (java.lang, java.util, etc.)
- Supporting files and configurations
Important: JRE does NOT include development tools like compiler (javac) or debugger. It's only for running Java programs, not developing them.
JDK (Java Development Kit)
The JDK is a complete kit for developing Java applications.
Contains:
- JRE (which includes JVM)
- Java Compiler (javac)
- Debugger (jdb)
- Java Documentation (javadoc)
- Archive tool (jar)
- Other development tools
Comparison Table
| Feature | JVM | JRE | JDK |
|---|---|---|---|
| Purpose | Execute bytecode | Run Java apps | Develop Java apps |
| Platform | Platform-dependent | Platform-dependent | Platform-dependent |
| Contains | Execution engine | JVM + libraries | JRE + dev tools |
| Compiler | No | No | Yes (javac) |
| For Users | End users | End users | Developers |
How Java Code Executes
Detailed Execution Flow
- Source Code (.java) - Human-readable code
- Compiler (javac) - Converts to bytecode
- Bytecode (.class) - Platform-independent intermediate code
- Class Loader - Loads bytecode into memory
- Bytecode Verifier - Security check
- Interpreter/JIT - Converts bytecode to machine code
- Execution - Program runs
JIT Compiler (Just-In-Time)
The JIT compiler improves performance by compiling frequently executed bytecode into native machine code at runtime.
- First run: Bytecode is interpreted (slower)
- Hotspot detection: JVM identifies frequently executed code
- Compilation: JIT compiles hotspots to native code
- Subsequent runs: Uses compiled native code (faster)
Interview Tip: Java is both compiled and interpreted. It's compiled to bytecode, then either interpreted or JIT-compiled to native code.
Java Collections Framework
What is the Collections Framework?
The Collections Framework is a unified architecture for storing and manipulating groups of objects.
Core Interfaces
List Interface
An ordered collection that allows duplicates and maintains insertion order.
ArrayList
Characteristics:
- Dynamic array implementation
- Fast random access O(1)
- Slow insertion/deletion O(n)
- Not synchronized (not thread-safe)
- Best for: Read-heavy operations
LinkedList
Characteristics:
- Doubly-linked list implementation
- Fast insertion/deletion O(1)
- Slow random access O(n)
- Implements both List and Deque
- Best for: Frequent insertions/deletions
Set Interface
A collection that does not allow duplicates.
HashSet
Characteristics:
- Hash table implementation
- No guaranteed order
- Fast operations O(1) average
- Allows one null element
- Best for: Uniqueness checking
TreeSet
Characteristics:
- Red-Black tree implementation
- Sorted in natural order or custom comparator
- Operations O(log n)
- No null elements
- Best for: Sorted unique elements
Map Interface
Stores key-value pairs. Keys must be unique.
HashMap
Characteristics:
- Hash table implementation
- No guaranteed order
- Fast operations O(1) average
- Allows one null key and multiple null values
- Not synchronized
- Best for: Fast key-value lookups
TreeMap
Characteristics:
- Red-Black tree implementation
- Sorted by keys
- Operations O(log n)
- No null keys
- Best for: Sorted key-value pairs
Queue Interface
Designed for FIFO (First-In-First-Out) operations.
PriorityQueue
Characteristics:
- Heap-based implementation
- Elements ordered by natural order or comparator
- Does not allow null
- Best for: Priority-based processing
Comparison: ArrayList vs LinkedList
| Operation | ArrayList | LinkedList |
|---|---|---|
| Access by index | O(1) | O(n) |
| Add at beginning | O(n) | O(1) |
| Add at end | O(1) amortized | O(1) |
| Remove by index | O(n) | O(n) |
| Memory | Less overhead | More overhead (pointers) |
Comparison: HashMap vs TreeMap
| Feature | HashMap | TreeMap |
|---|---|---|
| Order | No order | Sorted by keys |
| Performance | O(1) | O(log n) |
| Null keys | One allowed | Not allowed |
| Implementation | Hash table | Red-Black tree |
Important Collection Methods
Interview Tip: Always consider thread safety. For concurrent access, use ConcurrentHashMap, CopyOnWriteArrayList, or Collections.synchronizedXxx() methods.
Memory Management
Java Memory Structure
Memory Areas in JVM
Heap Memory
The heap is where all objects and instance variables are stored.
- Shared among all threads
- Created at JVM startup
- Garbage collection happens here
- Size controlled by: -Xms (initial) and -Xmx (maximum)
Young Generation
- Eden Space - Where new objects are allocated
- Survivor Spaces (S0, S1) - Objects that survive one GC cycle
- Minor GC occurs here frequently
Old Generation (Tenured)
- Long-lived objects promoted from Young Gen
- Major GC (Full GC) occurs here
- Slower but less frequent collection
Stack Memory
The stack stores method calls and local variables.
- One stack per thread
- LIFO (Last-In-First-Out) structure
- Stores: Local variables, method parameters, return addresses
- Each method call creates a stack frame
- Automatically cleared when method returns
- Size controlled by: -Xss
Stack Frame Contains:
- Local variable array
- Operand stack
- Frame data (constant pool reference, etc.)
Heap vs Stack
| Feature | Heap | Stack |
|---|---|---|
| Storage | Objects, instance variables | Method calls, local variables |
| Access | Slower | Faster |
| Size | Larger | Smaller |
| Lifetime | Until GC collects | Method execution only |
| Thread Safety | Shared (requires sync) | Thread-local (safe) |
| Error | OutOfMemoryError | StackOverflowError |
Example: Memory Allocation
What happens:
age- Primitive, stored directly in stackname- Reference in stack, "John" object in heapp- Reference in stack, Person object in heap- When method returns, stack variables cleared, heap objects remain until GC
Garbage Collection
Garbage Collection (GC) automatically frees memory by removing unreferenced objects.
When Does GC Run?
- When heap memory is low
- When System.gc() is called (not guaranteed)
- At JVM's discretion
Types of GC
- Minor GC - Cleans Young Generation (fast, frequent)
- Major GC - Cleans Old Generation
- Full GC - Cleans entire heap (slow, infrequent)
GC Algorithms
- Serial GC - Single-threaded, for small apps
- Parallel GC - Multiple threads, for throughput
- G1 GC - Default since Java 9, balances latency and throughput
- ZGC - Low latency, large heaps
Making Objects Eligible for GC
finalize() Method
Deprecated: finalize() is deprecated since Java 9. Use try-with-resources or Cleaner API instead.
Memory Leaks in Java
Yes, Java can have memory leaks! Common causes:
- Unclosed resources - Streams, connections not closed
- Static collections - Objects added but never removed
- Listeners not removed - Event listeners keeping references
- ThreadLocal misuse - Not cleaning up ThreadLocal variables
- Custom cache - Without eviction policy
Best Practices
- Use try-with-resources for auto-closeable objects
- Set references to null when done (especially in long-lived objects)
- Use weak references for caches
- Monitor memory usage with tools (VisualVM, JConsole)
- Tune JVM parameters based on application needs
Multithreading
Understanding Multithreading
What is a Thread?
A thread is the smallest unit of execution within a process. It's a lightweight subprocess.
Process vs Thread
| Process | Thread |
|---|---|
| Heavyweight | Lightweight |
| Separate memory space | Shared memory space |
| Expensive creation | Cheap creation |
| IPC needed for communication | Direct communication |
Creating Threads
Method 1: Extending Thread Class
Method 2: Implementing Runnable (Preferred)
Why Runnable is preferred: Java doesn't support multiple inheritance. Implementing Runnable allows your class to extend another class.
Thread Lifecycle
States Explained:
- New - Thread created but not started
- Runnable - Ready to run, waiting for CPU
- Running - Executing code
- Blocked - Waiting for monitor lock
- Waiting - Waiting indefinitely for another thread
- Timed Waiting - Waiting for specified time
- Terminated - Finished execution
Important Thread Methods
Synchronization
Synchronization prevents multiple threads from accessing shared resources simultaneously, avoiding race conditions.
Synchronized Method
Synchronized Block
Why Synchronization?
Inter-Thread Communication
Threads can communicate using wait(), notify(), notifyAll().
Important: wait(), notify(), and notifyAll() must be called from synchronized context.
Deadlock
Deadlock occurs when two or more threads are blocked forever, waiting for each other.
Preventing Deadlock:
- Always acquire locks in same order
- Use timeout with tryLock()
- Avoid nested locks
- Use concurrent collections
Executor Framework (Java 5+)
Modern way to manage threads using thread pools.
Types of Thread Pools:
- newFixedThreadPool(n) - Fixed number of threads
- newCachedThreadPool() - Creates threads as needed
- newSingleThreadExecutor() - Single worker thread
- newScheduledThreadPool(n) - For scheduled tasks
Volatile Keyword
volatile ensures:
- Variable is always read from/written to main memory
- Prevents caching in thread-local memory
- Guarantees visibility across threads
- Does NOT guarantee atomicity (use synchronized or Atomic classes)
Atomic Classes
Thread-safe without synchronization overhead.
Exception Handling
Exception Handling in Java
What is an Exception?
An exception is an unwanted or unexpected event that disrupts the normal flow of program execution.
Exception Hierarchy
Checked vs Unchecked Exceptions
| Feature | Checked | Unchecked |
|---|---|---|
| When checked | Compile time | Runtime |
| Must handle? | Yes (or declare) | No |
| Extends | Exception class | RuntimeException |
| Examples | IOException, SQLException | NullPointerException |
Try-Catch-Finally
Rules:
- Multiple catch blocks allowed
- Specific exceptions must come before general ones
- finally block always executes (even if return in try/catch)
- finally only skipped if System.exit() or fatal error
Throw vs Throws
throw (keyword)
throws (declaration)
| throw | throws |
|---|---|
| Used inside method | Used in method signature |
| Throws exception object | Declares exception types |
| Only one exception at a time | Multiple exceptions allowed |
Custom Exceptions
Try-With-Resources (Java 7+)
Requirements:
- Resource must implement AutoCloseable
- close() called automatically in reverse order
- Cleaner than finally block
Multi-Catch (Java 7+)
Common Exceptions
Best Practices
- Catch specific exceptions, not generic Exception
- Don't catch Throwable or Error
- Never leave catch block empty
- Use try-with-resources for AutoCloseable resources
- Log exceptions properly
- Don't use exceptions for flow control
- Create custom exceptions for domain-specific errors
Exception Propagation
If exception is not caught, it propagates up the call stack until handled or program terminates.
Types of Classes
Types of Classes in Java
1. Regular Class
2. Abstract Class
Cannot be instantiated. May contain abstract methods (without body) and concrete methods.
3. Final Class
Cannot be extended/inherited.
4. Static Nested Class
Static class defined inside another class. Can access only static members of outer class.
5. Inner Class (Non-static Nested Class)
Non-static class inside another class. Can access all members of outer class.
6. Anonymous Inner Class
Class without a name, created on-the-fly. Used for one-time use.
7. Local Inner Class
Class defined inside a method. Scope limited to that method.
8. Singleton Class
Ensures only one instance of the class exists.
9. POJO (Plain Old Java Object)
Simple class with private fields, getters, and setters. No special restrictions.
10. Immutable Class
State cannot be changed after creation.
Rules for Immutable Class:
- Declare class as
final - Make all fields
private final - No setters
- Initialize all fields in constructor
- Return copies of mutable objects
Comparison Table
| Type | Can Instantiate? | Can Inherit? | Use Case |
|---|---|---|---|
| Regular | Yes | Yes | General purpose |
| Abstract | No | Yes | Base class template |
| Final | Yes | No | Prevent inheritance |
| Static Nested | Yes | Yes | Logical grouping |
| Inner | Yes (via outer) | Yes | Access outer members |
| Singleton | One instance only | Usually no | Global access point |
Interview Tip: Know when to use each type. Abstract for templates, Final for security, Singleton for resource management, Immutable for thread safety.
Data Types & Keywords
Java Data Types
Primitive Data Types
Java has 8 primitive data types:
| Type | Size | Range | Default |
|---|---|---|---|
| byte | 1 byte | -128 to 127 | 0 |
| short | 2 bytes | -32,768 to 32,767 | 0 |
| int | 4 bytes | -2³¹ to 2³¹-1 | 0 |
| long | 8 bytes | -2⁶³ to 2⁶³-1 | 0L |
| float | 4 bytes | ~6-7 decimal digits | 0.0f | >
| double | 8 bytes | ~15 decimal digits | 0.0d |
| char | 2 bytes | 0 to 65,535 (Unicode) | '\u0000' |
| boolean | 1 bit | true or false | false |
Examples
Reference Types
All objects and arrays are reference types:
Type Casting
Widening (Implicit)
Narrowing (Explicit)
Important Java Keywords
Access Modifiers
- public - Accessible everywhere
- private - Accessible only within class
- protected - Accessible within package and subclasses
- default (no keyword) - Package-private
Non-Access Modifiers
- static - Belongs to class, not instance
- final - Cannot be modified/inherited/overridden
- abstract - Incomplete, must be overridden
- synchronized - Thread-safe method
- volatile - Variable in main memory
- transient - Skip during serialization
Other Important Keywords
- this - Refers to current object
- super - Refers to parent class
- new - Creates new object
- instanceof - Checks object type
- return - Exits method with value
- break - Exits loop or switch
- continue - Skips to next iteration
- extends - Inherits from class
- implements - Implements interface
- throws - Declares exceptions
- throw - Throws exception
Wrapper Classes
Each primitive has a corresponding wrapper class:
| Primitive | Wrapper Class |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
Autoboxing & Unboxing
var Keyword (Java 10+)
Interview Tip: Understanding the difference between primitives (stored in stack, passed by value) and objects (stored in heap, passed by reference) is crucial.