Hook: Think of Java like a car: the JVM is the engine, the JRE is the engine plus the parts needed to drive, and the JDK is the full garage with tools to build and fix the car.
Question: Difference between JDK, JRE, and JVM.
Answer: These are three layers of the Java platform. The JVM (Java Virtual Machine) is the runtime engine that executes Java bytecode. The JRE (Java Runtime Environment) is the JVM plus the standard libraries and files needed to run Java programs. The JDK (Java Development Kit) is the JRE plus developer tools like javac, jar, and javadoc for building Java applications.
Interview-Ready Answer: I explain it as three layers. The JVM is the piece that actually runs Java bytecode. The JRE is the JVM plus the core libraries needed to run apps, and the JDK is the full package for developers because it includes the JRE plus tools such as javac to compile code. A useful modern detail is that many Java 11+ distributions do not ship a separate end-user JRE anymore, so in practice people usually install a JDK and then build a smaller runtime if needed.
Detailed Explanation: The simplest way to remember it is:
JVM = the machine that understands and runs bytecode (the portable instructions produced by the compiler).JRE = JVM + standard Java libraries + files needed to run programs.JDK = JRE + tools needed to develop programs..java source code.javac compiler from the JDK turns source into .class files containing bytecode.| Part | Main job | Contains | Can compile? | Can run? |
|---|---|---|---|---|
| JVM | Execute bytecode | Class loading, JIT, GC | No | Yes |
| JRE | Run apps | JVM + libraries | No | Yes |
| JDK | Build apps | JRE + tools | Yes | Yes |
jlink make that easier.UnsupportedClassVersionError.ToolProvider.getSystemJavaCompiler() returns null, which is a classic sign that you are not on a full JDK.Memory hook: Run, Run-with-libraries, Run-and-build: JVM runs bytecode, JRE runs with libraries, JDK runs and builds.
Real-world story: Imagine a checkout service for an e-commerce app. Developers build it with a JDK on their laptops, CI compiles it with javac, and production containers only need a runtime because they are just launching the already-compiled service. The JVM is the part inside the container that actually executes the bytecode for payment validation, discount calculation, and order placement.
What goes wrong when someone misunderstands the difference? A common outage is deploying a build compiled on Java 21 to servers still running an older Java 17 JVM. The service starts, then immediately crashes with UnsupportedClassVersionError in the logs, pods restart-loop, and users see checkout failures or long delays. Another failure is a team using JavaCompiler in production code, only to discover that the runtime image does not include compiler tools, so startup fails with a message like “No system Java compiler available.”
The lesson: the JDK is for creating Java software, the JRE is for running it, and the JVM is the execution engine underneath both.
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
public class Main {
public static void main(String[] args) throws Exception {
System.out.println("Running on Java " + System.getProperty("java.version"));
System.out.println("JVM: " + System.getProperty("java.vm.name"));
// This API is only available when a full JDK is present.
// If it is missing, you are effectively on a runtime-only setup.
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
if (compiler == null) {
System.out.println("No system Java compiler found.");
System.out.println("This usually means you are running on a JRE-like runtime, not a full JDK.");
return;
}
Path tempDir = Files.createTempDirectory("jdk-jre-jvm-demo");
Path sourceFile = tempDir.resolve("GeneratedHello.java");
// We generate a tiny class, compile it, and load it dynamically.
// That shows the JDK doing work the JVM alone cannot do.
String source = ""
+ "public class GeneratedHello {\n"
+ " public String greet() { return \"Hello from compiled bytecode!\"; }\n"
+ "}\n";
Files.writeString(sourceFile, source, StandardCharsets.UTF_8);
// -d makes the compiler put .class files in our temp directory.
int result = compiler.run(null, null, null, "-d", tempDir.toString(), sourceFile.toString());
if (result != 0) {
System.out.println("Compilation failed with exit code: " + result);
return;
}
try (URLClassLoader loader = URLClassLoader.newInstance(new URL[] { tempDir.toUri().toURL() })) {
Class<?> type = Class.forName("GeneratedHello", true, loader);
Object instance = type.getDeclaredConstructor().newInstance();
Method greet = type.getMethod("greet");
System.out.println("Loaded class: " + type.getName());
System.out.println("Invocation result: " + greet.invoke(instance));
}
// Edge case: cleanup is best-effort. The concept matters more than temp-file hygiene.
try {
Files.deleteIfExists(sourceFile);
} catch (IOException ignored) {
// Intentionally ignored.
}
}
}Follow-up & Tricky Questions:
javac. The JVM reads bytecode, which is why the same .class file can run on different operating systems if the JVM version is compatible.Common Mistakes:
Memory Hook: JVM = runs, JRE = runs with libraries, JDK = runs and builds. If you can compile, you need the JDK; if you only execute, you need the runtime; the JVM is the engine inside both.
Cheat Sheet:
JVM executes bytecode.JRE = JVM + core libraries.JDK = JRE + developer tools.javac comes with the JDK, not the JRE..class bytecode before running.Practice Tasks:
java -version and javac -version; notice both are present..class file, and run it with the java launcher.