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 thejava.util.concurrentpackage), rather than bolted on through external OS libraries. - Architecture-Neutral & High Performance: Primitive type sizes are strictly standardized across all hardware (e.g., an
intis 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.
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 fromjava.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 astatic { ... }initialization block beforemainwas checked. However, from Java 7 onwards, the JVM explicitly validates the presence of the standardpublic static void main(String[] args)signature before initializing the class, throwing aNoSuchMethodError: 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), andjavadoc(documentation generator).
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?
- Method Area / Metaspace: Stores class-level structure, static variables, bytecode instructions, and constant pool. (Shared across all threads).
- Heap Area: Allocates all objects and arrays created via
new. Managed automatically by Garbage Collector. (Shared across all threads). - 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.
- PC (Program Counter) Register: Holds the memory address of the JVM instruction currently being executed by each thread.
- 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, somainmust be static.void: The return type indicating thatmainreturns no value upon completion. In Java, process exit status is returned viaSystem.exit(int code).main: The fixed identifier required by the JVM specification.String[] args: An array ofStringobjects representing command-line arguments passed to the program at startup.
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 maininstead ofpublic static void main? Yes! In Java, the order of access specifier (public) and access modifier (static) does not matter. Bothpublic staticandstatic publicare 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 multiplemainmethods in the same class with different parameters (e.g.main(int a)). However, the JVM will exclusively callmain(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:
- Stage 1 — Compilation: The
javaccompiler reads your human-readable.javasource code and translates it into a.classfile containing platform-independent bytecode instructions. Crucially, bytecode is not machine code for any real CPU. - Stage 2 — Execution (JVM Interpretation & JIT Compilation): When you run
java MyProg, the JVM loadsMyProg.classinto 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.
💡 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
.classfile, 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.