What is Java?
Java is a statically typed, object-oriented, compiled language that runs on the Java Virtual Machine (JVM). Its core promise β "Write Once, Run Anywhere" (WORA) β means bytecode compiled on any platform runs unchanged on any other platform with a JVM installed. No recompilation needed.
Released in 1995 by Sun Microsystems, Java became the dominant language for enterprise software and remains one of the top 2 languages by usage in 2026. It powers the backend of companies like LinkedIn, Netflix, Uber, and most of the global banking infrastructure.
- Backward compatibility β code written in Java 5 compiles on Java 25. No other major language can claim this.
- The JVM ecosystem β Kotlin, Scala and Groovy all run on the JVM and interoperate seamlessly with Java code.
- Enterprise inertia + active innovation β massive existing codebases combined with a 6-month release cadence since Java 9.
- Tooling maturity β IntelliJ, Maven/Gradle, Spring, JUnit, Mockito, Testcontainers. An ecosystem unmatched in productivity.
How Java Works: Compile Once, Run Anywhere
Unlike C or C++ which compile directly to platform-specific machine code, Java uses a two-stage process. This is what enables platform independence.
/*
* YOUR CODE BYTECODE NATIVE CODE
* (HelloWorld.java) (HelloWorld.class) (Platform-specific)
* β β β
* β βββββββββββββββ β ββββββββββββββββ β
* βββΆβ javac ββββ΄ββΆβ JVM ββββΆβ
* β (compiler) β β (java cmd) β β
* βββββββββββββββ ββββββββββββββββ β
* β
* ββββββββββββββββΌβββββββββββββββ
* ββββββΌβββββ βββββββΌβββββ βββββββΌββββββ
* β Windows β β macOS β β Linux β
* β JVM β β JVM β β JVM β
* βββββββββββ ββββββββββββ βββββββββββββ
*
* The SAME .class file runs on ANY platform with a JVM installed.
*/
Your first program
// File: HelloWorld.java (filename must match public class name)
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
# Compile β produces HelloWorld.class (bytecode)
javac HelloWorld.java
# Run β JVM executes the bytecode
java HelloWorld
# Java 11+ shortcut: compile and run in one step
java HelloWorld.java
# Java 25+: compact source files drop the class/main boilerplate entirely
# for scripts and small programs β see the "Which version" box below
JVM Architecture
The JVM is not a simple interpreter. It has three main components working together:
/*
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
* β Java Virtual Machine β
* β β
* β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β
* β β Class Loader β β
* β β β’ Loads .class files into memory β β
* β β β’ Verifies bytecode integrity β β
* β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β
* β β β
* β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β
* β β Runtime Data Areas β β
* β β ββββββββββββ¬βββββββββββ¬ββββββββββββββββββββββββββ β
* β β β Method β Heap β Stack (per thread) ββ β
* β β β Area β (Objects)β (Local vars, frames) ββ β
* β β ββββββββββββ΄βββββββββββ΄ββββββββββββββββββββββββββ β
* β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β
* β β β
* β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β
* β β Execution Engine β β
* β β β’ Interpreter: line-by-line for cold code β β
* β β β’ JIT Compiler: compiles hot paths to native β β
* β β β’ GC: automatic heap memory management β β
* β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
*/
The JVM starts interpreting bytecode, then identifies "hot" code paths executed frequently. Those paths get compiled to native machine code and cached. Result: after warmup, Java performance is comparable to C++ for most workloads. The JVM can even outperform static compilers by applying runtime-only optimizations (e.g. inlining based on actual call patterns). Java 25 pushes this further with ahead-of-time method profiling β usage data from a prior run can prime the JIT before the application even sees traffic, cutting warmup time for short-lived services.
What Can You Build With Java?
| Domain | Examples | Key Technologies |
|---|---|---|
| Enterprise backends | LinkedIn, Netflix, Uber, most banks | Spring Boot, Jakarta EE |
| Microservices | REST APIs, event-driven systems | Spring Boot, Quarkus, Micronaut |
| Android apps | Millions of apps on Play Store | Android SDK (Kotlin preferred, Java supported) |
| Big Data | Data pipelines, stream processing | Apache Kafka, Spark, Hadoop, Flink |
| Cloud / serverless | AWS Lambda, GCP Functions | Quarkus + GraalVM native image |
| Desktop / tools | IntelliJ IDEA, Minecraft, Eclipse | JavaFX, Swing |
Java LTS Versions: What Actually Matters
Java releases every 6 months but only LTS (Long-Term Support) versions get multi-year patches. Use LTS for production. Non-LTS releases β including 22, 23, 24 and 26 β are 6-month previews: fine for trying a language feature early, not for a production baseline.
| Version | Year | Key Features | Status |
|---|---|---|---|
| Java 8 | 2014 | Lambdas, Streams, Optional, new Date/Time API | Still widespread in legacy systems |
| Java 11 | 2018 | var, HTTP Client, new String methods |
Legacy baseline; migrate off if you still can |
| Java 17 | 2021 | Records, Sealed classes, Pattern matching, Text blocks | Minimum viable baseline for new work β still fully supported |
| Java 21 | 2023 | Virtual threads (Loom), Pattern matching in switch, Sequenced collections | Previous LTS β solid, still widely deployed in production |
| Java 25 | 2025 | Scoped Values, Compact source files, Flexible constructor bodies, AOT method profiling, Generational Shenandoah (stable) | β Current LTS β the target for new projects |
New project: Java 25. It's been in production for close to a year and
carries Oracle's stated 8-year support commitment β no reason to start lower.
Existing project on 8 or 11: Plan migration to 17 minimum, then 25 when the
codebase allows it. The compiler flags deprecated APIs you depend on at each step.
Existing project on 17 or 21: Not urgent. Both are still fully supported LTS
lines; move to 25 on your team's normal upgrade cadence, not as an emergency.
Learning: Java 21 or 25 so you learn modern syntax (records, var, text blocks,
virtual threads) from day one. Don't learn on 8 unless you're maintaining legacy code that
requires it.
Java 26 shipped in March 2026. It is not LTS β it's a routine 6-month feature release, same category as 22, 23 and 24 before it. It doesn't replace Java 25 as the production target; the next LTS is expected roughly two years out, following the established 8 β 11 β 17 β 21 β 25 cadence. Knowing this distinction β LTS vs. feature release β is itself a fair interview question; conflating "newest version" with "version to use in production" is a common junior mistake.
Java vs Modern Alternatives
The honest comparison β not "Java is best everywhere", but when each language genuinely wins:
| Scenario | Best Choice | Why |
|---|---|---|
| Enterprise backend / microservices | Java / Kotlin | Spring Boot ecosystem, team scalability, tooling depth |
| ML / AI / Data Science | Python | PyTorch, pandas, scikit-learn. Java has no equivalent here. |
| Systems / low-level / no GC | Rust / C++ | Direct memory control, zero GC pauses |
| Cloud-native / fast startup | Go / Java+GraalVM | Go starts in ms natively; GraalVM native image and Java 25's AOT improvements close the gap for Java |
| Android development | Kotlin | Google's official preference since 2017. Java still works but Kotlin is idiomatic. |
| Web frontend | TypeScript | Java doesn't run in the browser (WASM experiments aside) |
Same name prefix, completely different languages. Java is compiled, statically typed, runs on the JVM, used for backend and Android. JavaScript is dynamic, runs in the browser and Node.js, used for frontend and web. The naming similarity was a 1995 marketing decision by Netscape. Don't confuse them in an interview.
Java in Production: What Seniors Actually Use
The gap between "learning Java" and "working with Java professionally" is significant. This is the real stack you'll encounter in enterprise teams:
The Standard Enterprise Stack (2026)
- Spring Boot 3.x β the de facto framework. Auto-configuration, embedded Tomcat/Netty, production-ready Actuator endpoints. Requires Java 17+; runs cleanly on 25.
- Spring Data JPA + Hibernate β ORM layer. Know the N+1 problem, lazy loading pitfalls, and when to drop to native queries or JOOQ.
- Spring Security + OAuth2/JWT β every production API needs it. Know the filter chain, not just the annotations.
- Apache Kafka β async communication between microservices. If you haven't used it in production, it's the single biggest gap most Java developers have.
- Docker + Kubernetes β Java apps run in containers. Knowing how to tune JVM memory for containers is not optional.
- Gradle β winning over Maven for new projects. Faster incremental builds, Kotlin DSL for type-safe build scripts.
JVM Flags Every Senior Must Know
// Container-aware memory β CRITICAL in Kubernetes
// Without this, JVM reads host memory instead of container limits
-XX:MaxRAMPercentage=75.0
// GC selection
// G1GC (default since Java 9): best for most web services
// ZGC (production since Java 15): sub-millisecond pauses regardless of heap size
// Generational Shenandoah (stable since Java 25): same low-pause goal as ZGC,
// different algorithm β worth benchmarking both under your actual load
-XX:+UseZGC -Xmx4g
// Virtual threads β the biggest concurrency change since Java 5 (Java 21+)
// In Spring Boot 3.2+ application.properties:
spring.threads.virtual.enabled=true
// That's it. Your app now handles dramatically more concurrent requests.
// Blocking I/O is fine again β virtual threads are cheap (< few KB each).
// Compact object headers (Java 25): shrinks per-object header from 12-16 to
// 8 bytes. Free heap-density win for object-heavy workloads β enable and measure.
-XX:+UseCompactObjectHeaders
Traditional platform threads cost ~1MB of stack memory each. With a 4GB heap you can run ~4,000 threads before OOM. A virtual thread costs a few KB β you can run millions concurrently. They unmount from the carrier thread while blocked on I/O, so blocking code is efficient again.
This eliminates the main reason to adopt reactive programming (WebFlux/Reactor) for most use cases. Imperative code is readable, testable, and now also scalable.
Important caveat: virtual threads do NOT help CPU-bound work. For heavy
computation, you still need ForkJoinPool or explicit parallelism.
Java 25 companion feature: Scoped Values (JEP 506, finalized in 25) solve a
problem virtual threads made worse β ThreadLocal doesn't scale cleanly to
millions of threads. Scoped Values are immutable, shared safely across a thread's lifetime,
and are the modern replacement for ThreadLocal in code written against virtual
threads.
Interview Questions: Junior vs Senior
Q: What does "Write Once, Run Anywhere" mean?
Java source is compiled to platform-independent bytecode. Any device with a JVM can run that
bytecode without recompilation. The JVM abstracts the platform differences.
Q: What's the difference between JDK, JRE and JVM?
JVM executes bytecode. JRE = JVM + standard libraries (enough to run Java programs). JDK =
JRE + compiler (javac) + tools (enough to develop Java programs). In production
you install JRE. On a dev machine you install JDK.
Q: Is Java pass-by-value or pass-by-reference?
Always pass-by-value. For objects, the value passed is the reference (pointer copy), not the
object itself. Reassigning the parameter inside a method doesn't affect the caller, but
mutating the object's state through the reference does.
Q: What is the difference between == and
.equals()?
== compares references (memory address). .equals() compares content.
Always use .equals() for Strings and objects. Exception: enums and primitives
can use ==.
Q: What's the difference between an LTS and a non-LTS Java release?
LTS (Long-Term Support) versions β 8, 11, 17, 21, 25 β get years of patches from Oracle and
other vendors. Non-LTS versions ship every 6 months in between (22, 23, 24, 26...) and receive
updates only until the next release. Production systems target LTS; non-LTS is for trying new
language features early.
Q: Explain the Java memory model. Where do objects and primitives live?
Objects live on the heap, managed by GC. Primitives and object references live on the thread
stack. Since Java 8, PermGen was replaced by Metaspace (native memory, no fixed limit by
default) β it stores class metadata. A common production issue is Metaspace growing unbounded
due to dynamic class generation (e.g. CGLIB proxies, Groovy scripts). Since Java 25, compact
object headers also shrink per-instance overhead on the heap itself β relevant when discussing
memory density for object-heavy workloads.
Q: What is the difference between G1GC, ZGC and Shenandoah?
G1GC (default since Java 9): generational, region-based, good general-purpose GC with
configurable pause targets (-XX:MaxGCPauseMillis). ZGC (production since Java
15): concurrent, sub-millisecond pauses regardless of heap size, ideal for latency-sensitive
systems. Shenandoah (Red Hat): same low-pause goal as ZGC via a different algorithm; its
generational mode was promoted from experimental to a stable product feature in Java 25,
closing most of the gap with ZGC's memory efficiency. For most REST APIs, G1GC is sufficient.
For trading systems or real-time apps with strict SLAs, benchmark ZGC and Generational
Shenandoah against your actual workload rather than assuming one is universally better.
Q: What problem do virtual threads solve, and what they don't?
Virtual threads solve the thread-per-request bottleneck: a platform thread blocked on I/O
holds ~1MB of stack and a kernel thread. Virtual threads unmount from the carrier thread while
blocked, making millions of concurrent blocking operations feasible. They do NOT help
CPU-bound work β for parallel computation, ForkJoinPool or parallel streams are
still the right tool. A related, more recent question: virtual threads exposed the weaknesses
of ThreadLocal at scale, which is why Scoped Values (JEP 506) were finalized in
Java 25 as the safer, immutable alternative for propagating context across threads.
Q: What is a memory leak in Java if GC manages memory?
GC only collects objects with no reachable references. A leak occurs when objects remain
reachable but are never actually used: static collections that grow without eviction,
unclosed resources (connections, streams β use try-with-resources), listeners never
deregistered, or incorrect hashCode() on mutable keys breaking HashMap
invariants. Diagnose with heap dumps via Eclipse MAT, VisualVM, or jmap.