› Module 1: Introduction to Java › 1.2 JVM, JRE, and JDK
M O D U L E

Module 1: Introduction to Java

Origins of Java, WORA philosophy, JVM/JRE/JDK architecture, and how bytecode executes across platforms.

1.1 History and Features of Java

Java was created by James Gosling, Mike Sheridan, and Patrick Naughton at Sun Microsystems, and was released to the public in 1995. Interestingly, it was not originally designed for the World Wide Web or desktop computers — the project began in 1991 (originally named Oak, after an oak tree outside Gosling's office, and later renamed to Java inspired by Indonesian coffee) as an effort to build reliable, hardware-independent software for interactive television and embedded consumer electronic devices.

That original goal shaped the language's most famous design promise, still repeated today: 'Write Once, Run Anywhere' (WORA).

To understand why that promise is so revolutionary, it helps to compare Java with languages like C or C++. When you compile a C program, the compiler translates your source code directly into machine instructions tailored for one specific operating system and processor architecture. A binary compiled on Windows x86_64 will not execute on Linux or macOS ARM64 without being completely recompiled from scratch. Java takes a fundamentally different approach: instead of compiling straight to native machine code, the Java compiler (javac) produces an intermediate, platform-neutral representation called bytecode (stored in .class files).

Bytecode is not tied to any physical CPU or operating system — it is tied exclusively to the Java Virtual Machine (JVM). As long as a computer has a JVM installed for its platform, it can execute that exact same .class file without recompilation. This mechanism delivers true cross-platform portability.

Core Architectural Features of Java

  • Object-Oriented: With the exception of the eight primitive types, everything in Java is modeled as a class or an object. This enforces clean modularity, code reuse, and encapsulation around real-world entities.
  • Robust & Memory-Safe: Java performs rigorous type checking at compile time, catching bugs before runtime. Furthermore, Java completely eliminates manual memory deallocation through automatic Garbage Collection (GC), preventing catastrophic memory leaks, double-free bugs, and dangling pointer corruptions.
  • Secure & Sandboxed: Java programs execute inside the managed sandbox of the JVM. Because Java eliminates direct, raw pointer arithmetic (unlike C/C++), untrusted applications cannot arbitrarily read or write to private physical RAM addresses or corrupt system structures.
  • Multithreaded: Concurrency is a first-class language feature built directly into the core runtime and standard library (via Thread, Runnable, the monitor lock, and the java.util.concurrent package), rather than bolted on through external OS libraries.
  • Architecture-Neutral & High Performance: Primitive type sizes are strictly standardized across all hardware (e.g., an int is always exactly 32 bits, two's complement, on every machine worldwide). The modern HotSpot JVM uses Just-In-Time (JIT) compilation to achieve speeds rivaling native code.
KEY TERM: Bytecode

The compact, platform-independent instruction set produced by the Java compiler (javac). It is not native machine code and cannot run directly on a physical CPU — it must be interpreted or compiled on the fly by a JVM.

💡 Placement & Interview Deep-Dive

  • Is Java 100% Pure Object-Oriented? No. Java is not 100% pure OOP because it retains the 8 primitive data types (int, char, boolean, etc.) which store raw scalar values directly on the stack without inheriting from java.lang.Object. Pure OOP languages (like Smalltalk) require everything to be an object. Java chose primitives for execution speed and low memory footprint.
  • Can we execute a Java program without a main() method? Historically in Java 6 and earlier, you could execute code in a static { ... } initialization block before main was checked. However, from Java 7 onwards, the JVM explicitly validates the presence of the standard public static void main(String[] args) signature before initializing the class, throwing a NoSuchMethodError: main.
  • Why does Java not support multiple inheritance with classes? To eliminate the classic Diamond Problem where a subclass inherits ambiguous method implementations from two superclasses. Java allows multiple inheritance of type and contract via interfaces.

1.2 JVM, JRE, and JDK

These three acronyms trip up almost every newcomer to Java because they sound similar and are closely interrelated. However, each serves a distinct role in the Java ecosystem, and understanding the differences is essential for configuring development environments and enterprise deployment pipelines.

The Three Architectural Layers

  • JVM (Java Virtual Machine): The innermost core execution engine. The JVM takes platform-independent bytecode instructions and translates them, instruction by instruction or via JIT compilation, into the native machine instructions of the host CPU. The JVM itself is platform-specific (there is a different JVM build for Windows x64, macOS ARM64, and Linux), but the bytecode it consumes is 100% identical.
  • JRE (Java Runtime Environment): The runtime package that wraps around the JVM. It bundles the JVM together with the core standard class libraries (java.lang, java.util, java.io, java.math) that every Java application needs to run. If your goal is only to run pre-compiled Java applications, the JRE is all that is required.
  • JDK (Java Development Kit): The complete software development bundle. It contains the entire JRE plus the full suite of developer tools required to write, compile, debug, and package Java software — including javac (the compiler), jdb (the debugger), jar (archive packager), and javadoc (documentation generator).
JDK (Java Development Kit) includes compiler (javac), debugger, tools JRE (Java Runtime Environment) includes JVM + core class libraries JVM (Java Virtual Machine) executes bytecode on this machine
Figure 1.2 — Each layer contains the one inside it: the JDK contains the JRE, and the JRE contains the JVM.
Rule of Thumb:

JDK to build, JRE to run, JVM to execute. Modern developers install the JDK, as it provides the complete set of tools and runtime libraries.

💡 Placement & Interview Deep-Dive: JVM Internal Memory Architecture

  • What are the 5 Run-Time Data Areas of the JVM?
    1. Method Area / Metaspace: Stores class-level structure, static variables, bytecode instructions, and constant pool. (Shared across all threads).
    2. Heap Area: Allocates all objects and arrays created via new. Managed automatically by Garbage Collector. (Shared across all threads).
    3. JVM Stack: Allocates a separate stack for each thread. For every method called, a Stack Frame is pushed containing local variables, operand stack, and partial results.
    4. PC (Program Counter) Register: Holds the memory address of the JVM instruction currently being executed by each thread.
    5. Native Method Stack: Holds native (C/C++) instructions executed through Java Native Interface (JNI).
  • What is the difference between Heap and Stack memory in Java? Primitive local variables and reference pointers live on the thread Stack (fast, auto-cleaned upon method return). Concrete object instances and array payloads live in Heap memory (survives across method calls, reclaimed by GC when unreferenced).

1.3 Structure of a Java Program

Unlike languages like C or Python that allow loose, top-level statements floating outside of any container, Java is purely object-oriented: every single piece of executable code must reside inside a class.

When you instruct the JVM to execute a program, it looks for a standardized, predefined entry point method with this exact signature:

public class HelloWorld { // class definition
    public static void main(String[] args) { // entry point
        System.out.println("Hello, World!");
    }
}

Anatomy of the main Method Signature

  • public: An access modifier that makes the method accessible from outside the class. The JVM launcher is outside your class, so it requires public visibility.
  • static: Allows the method to be invoked without having to instantiate an object of the class first. At startup, no objects exist yet, so main must be static.
  • void: The return type indicating that main returns no value upon completion. In Java, process exit status is returned via System.exit(int code).
  • main: The fixed identifier required by the JVM specification.
  • String[] args: An array of String objects representing command-line arguments passed to the program at startup.
Crucial File Naming Rule:

In Java, the source file name must exactly match the public class name, including case sensitivity, followed by the .java extension. A file defining public class MyProgram must be named MyProgram.java; otherwise, javac will throw a compilation error.

💡 Placement & Interview Deep-Dive

  • Can we write static public void main instead of public static void main? Yes! In Java, the order of access specifier (public) and access modifier (static) does not matter. Both public static and static public are 100% valid.
  • Can we use Varargs in the main method? Yes! public static void main(String... args) is completely valid and accepted by the JVM because Varargs is compiled down to an array under the hood.
  • Can we overload the main() method? Yes, you can define multiple main methods in the same class with different parameters (e.g. main(int a)). However, the JVM will exclusively call main(String[] args) as the program entry point; other overloaded versions must be called manually.

1.4 Compilation and Execution Process

Where a traditional C toolchain compiles source code directly to a native CPU executable in a single step, Java divides the execution pipeline into two distinct stages:

  1. Stage 1 — Compilation: The javac compiler reads your human-readable .java source code and translates it into a .class file containing platform-independent bytecode instructions. Crucially, bytecode is not machine code for any real CPU.
  2. Stage 2 — Execution (JVM Interpretation & JIT Compilation): When you run java MyProg, the JVM loads MyProg.class into memory, verifies bytecode safety, and executes instructions. It employs a hybrid execution model: an interpreter executes bytecode immediately for rapid startup, while a Just-In-Time (JIT) compiler monitors runtime execution and compiles frequently executed ("hot") code paths directly into native CPU machine instructions.
MyProg.java (Source Code) javac MyProg.class (Bytecode) run JVM interprets / JIT-compiles bytecode into native machine instructions
Figure 1.4 — From source code, to portable bytecode, to JVM execution. The same .class file runs unmodified on any OS with a JVM.

💡 Placement & Interview Deep-Dive

  • What is the difference between JIT Compiler and Standard Interpreter? An interpreter translates bytecode instructions one by one every time they are executed (slow for repeated loops). The JIT compiler monitors code execution profiling; once a method or loop reaches an execution threshold ("hot spot"), JIT compiles that entire chunk into physical machine code and stores it in code cache, executing at native hardware speed.
  • What does the JVM Bytecode Verifier do? Before executing any .class file, the ClassLoader passes bytecode to the Bytecode Verifier. It checks that the code adheres to JVM specifications, does not forge pointers, violate access permissions, or overflow operand stacks, guaranteeing system security against malicious class files.
MODULE COMPREHENSIVE QUIZ

Module 1 Final Quiz

Test your understanding across all 4 topics of this module with interview-grade questions, tricky edge cases, and code output predictions.

Take Module 1 Final Quiz →
Yukti Mascot