javajdkjrejvmbytecodejlinkinterview·9 min read

Difference Between JDK, JRE and JVM

The JVM runs compiled bytecode. The JRE is the JVM plus the standard class library, so it can run a Java program but not compile one. The JDK is the JRE plus the development tools — javac first among them — so it can do both. Each contains the one below it, which is why installing a JDK is all you ever need to do.

The short answer, and the one relationship behind it

Three names, one install, three layers that sit inside each other:

Layer What it is What it can do
JVM The engine that executes compiled bytecode Run a .class file
JRE JVM + the standard class library Run a Java program
JDK JRE + the development tools Compile and run

Each one contains the one below it. That single relationship answers most of the question: you never choose between them, because installing a JDK gives you all three. The reason the question keeps coming up is that all three names describe parts of one directory, and nothing in that directory is labelled.

The rest of this article takes one file and follows it across all three layers, then shows where the neat nesting diagram stops being true — because on a modern Java version, it does.

The JVM is a specification, not a program

The Java Virtual Machine is defined by a document: The Java Virtual Machine Specification, which is versioned alongside the language. "The JVM" is not one piece of software; it is a contract that many pieces of software implement.

The most useful sentence in that specification is this one: the Java Virtual Machine knows nothing of the Java programming language, only of a particular binary format — the class file format.

Read that twice, because it dissolves the confusion. The JVM cannot read .java files. It has never been able to. It reads class files: a binary format containing an instruction set (bytecode — machine instructions for a machine that does not physically exist) plus a symbol table. The specification is explicit that this makes the JVM independent of implementation technology, host hardware and host operating system, and that it is not inherently interpreted — an implementation may compile bytecode down to a real CPU's instructions, or implement it in silicon.

That is what "write once, run anywhere" actually means, stated precisely: the class file is the portable artefact. The JVM is the part that is different on every platform, so your class file does not have to be.

The JRE is the JVM plus the library your code assumes

A class file full of bytecode is not yet a running program, because your code refers to things it did not write. System.out.println is not a JVM instruction — it is a method on a class that has to exist somewhere before your program can start.

That "somewhere" is the standard class library, and JRE — Java Runtime Environment — is the name for the JVM and that library packaged together. It is what you need on a machine that only ever runs Java software.

What it deliberately does not contain is a compiler. A JRE cannot turn Hello.java into Hello.class. If you have ever installed Java, run someone's application successfully, and then found there was no compiler on the machine, you installed a JRE.

Note

"The class library" is not one blob any more. Since Java 9 the runtime is divided into modules, and the one every Java program needs is java.base — it holds java.lang, java.util, java.io and the rest of the core API. That detail matters later, when we build a runtime by hand.

The JDK is the JRE plus the tools that make class files

The JDK — Java Development Kit — is the JRE with the development tools added. The important ones, and what each is for:

Tool What it does
javac Compiles .java source into class files
java Starts a JVM and runs a class
javap Disassembles a class file so you can read the bytecode
jlink Assembles a custom runtime image
jar Packages class files into an archive
jshell An interactive prompt for Java expressions

Note where java sits in that table. The launcher belongs to the runtime, not to the tools — which is exactly why a JRE can run your program without being able to build it. The JDK adds the producers of class files; the JRE already had the consumer.

Follow one file across all three layers

Definitions are easy to recite and hard to trust. Here is the whole boundary in eight commands. Everything below was run inside the eclipse-temurin:21-jdk container image, so you can reproduce every number:

docker run --rm -it eclipse-temurin:21-jdk bash

Start with three lines of source:

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, JVM");
    }
}

Compile it — this is the JDK's job:

javac Hello.java
ls -l Hello.class
## -rw-r--r-- 1 root root 414 Hello.class

414 bytes. Three lines of source became a binary artefact, and javac — a JDK tool — is the only thing in this story that could have produced it.

Look at what came out. The first eight bytes tell you what the JVM checks before it will touch a file:

od -An -tx1 -N8 Hello.class
## ca fe ba be 00 00 00 41

cafebabe is the magic number the specification requires at the start of every class file. The two bytes after it are the minor version (00 00), and the two after that are the major version: 00 41, which is 65 in decimal. Java SE 21 emits major version 65, and a JDK 21 JVM accepts anything from 45 to 65. This is the number behind UnsupportedClassVersionError: a class compiled by a newer JDK than the JVM running it carries a major version the JVM was never told about, and it refuses the file rather than guessing.

Read the bytecode, because "the JVM executes instructions" is much less convincing than seeing them:

javap -c Hello
public static void main(java.lang.String[]);
  Code:
     0: getstatic     #7   // Field java/lang/System.out:Ljava/io/PrintStream;
     3: ldc           #13  // String Hello, JVM
     5: invokevirtual #15  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     8: return

Four instructions. Fetch the static field System.out, load the string constant, call println on it, return. Nothing here mentions Java the language — this is the binary format the specification says is all the JVM knows about. That is not a technicality: the same specification states that any language whose functionality can be expressed in a valid class file can be hosted by the JVM, which is precisely why other languages target it.

Run it — this is the JRE's job:

java Hello
## Hello, JVM

And notice what that line needed: a JVM to execute those four instructions, plus a class library to supply java.lang.System and java.io.PrintStream. JVM plus library — a JRE. The compiler played no part.

Where the neat diagram stops being true

Everything above is the answer an interviewer wants. It is also, on any current Java version, slightly out of date. Two things changed.

Oracle stopped shipping a separate JRE. JEP 220 restructured the JDK and JRE into modular run-time images, and Oracle's JDK 11 release notes record the consequence plainly: on Windows and macOS, installing the JDK in previous releases optionally installed a JRE; in JDK 11 that is no longer an option. If you have looked for a JRE download recently and found only JDKs, that is why.

It has not vanished from the ecosystem, though — that is a common overcorrection. Other OpenJDK distributions still publish standalone JRE packages: Eclipse Temurin ships one for Java 21 as OpenJDK21U-jre_x64_linux_hotspot_21.0.12.1_1.tar.gz, alongside the JDK.

And the replacement is better than the thing it replaced. jlink assembles a set of modules and their dependencies into a custom runtime image. Instead of choosing between "the full JDK" and "the standard JRE", you build the runtime your application actually needs.

Watch how sharp the boundary gets. The JDK image in that container is 295 MB and carries 69 modules (java --list-modules | wc -l). Now build a runtime with only the core:

jlink --add-modules java.base --strip-debug --no-header-files --no-man-pages \
  --output /tmp/mini
du -sh /tmp/mini
## 52M   /tmp/mini
ls /tmp/mini/bin
## java  keytool

52 MB instead of 295, and its bin directory contains two programs. That is a JRE in everything but name — hand-built, containing exactly one module. It runs the class we compiled earlier:

/tmp/mini/bin/java -cp /tmp Hello
## Hello, JVM

Here is the part worth remembering. Since JEP 330, Java 11 and later can run a single source file directly, without a separate compile step:

java /tmp/Hello.java
## Hello, JVM

That looks like the JVM compiling Java, which would break the whole model. It is not: the launcher hands the source to the compiler that is also in your JDK. Point the same command at our hand-built runtime and the illusion collapses:

/tmp/mini/bin/java /tmp/Hello.java
## Exception in thread "main" java.lang.InternalError:
## Module jdk.compiler not in boot Layer

There it is, named in an error message: jdk.compiler. The runtime with only java.base can run compiled code all day and cannot compile a line, because compilation lives in a module a runtime image does not have to include. That error is the JDK/JRE distinction, printed by the JVM itself.

Interview tip

This is the follow-up question interviewers actually ask: "so what does java Hello.java prove about the JRE?" The answer is nothing — the convenience is a JDK feature. The layers did not merge; the launcher just learned to call the compiler for you.

So what should you install?

Install a JDK. That is the whole recommendation, and it holds for every situation a developer is in:

  • On your own machine, you will compile something eventually, and javac is the only thing that can do it. Installing Java 21 on Windows walks through picking a distribution and setting it up.
  • On a server, a Java application is a jar you hand to java. A Eureka service-discovery server is a good example — a jar, a JVM, no compiler needed at runtime. A JDK still costs you nothing but disk.
  • In a container image, the size difference stops being academic, and this is where jlink earns its place: build the runtime, copy in the jar, and ship 52 MB instead of 295. If you are choosing how to run those images, Docker vs Kubernetes sorts out which tool does what.

Common mistake

Installing a JRE "because production only runs code", and then needing a compiler on that box at the worst possible moment. The whole JDK is 295 MB on a machine that has gigabytes. Save the minimal runtime for the container image, where you build exactly what you need with jlink rather than downloading a general-purpose one.

How to answer this in an interview

Three sentences, in this order, and stop:

  1. The JVM executes bytecode — it reads class files and knows nothing about the Java language.
  2. The JRE is the JVM plus the standard class library: enough to run a program, not to compile one.
  3. The JDK is the JRE plus the development tools, javac first among them — which is why the JDK is what you install.

If you want to show you have actually looked: add that Oracle stopped shipping a separate JRE in JDK 11, and that jlink now builds a runtime containing only the modules an application needs. That is the difference between reciting a diagram and having used the thing.

Frequently asked questions

Do I need to install the JRE separately if I already have the JDK?
No. A JDK contains a complete runtime, so a machine with a JDK can already run Java programs. Oracle stopped offering a bundled JRE with the JDK installer in JDK 11, which is why recent download pages list only JDKs.
Can the JVM run languages other than Java?
Yes. The specification says the JVM knows nothing of the Java programming language, only the class file format, and that any language whose functionality can be expressed in a valid class file can be hosted on it. That is why other languages target the JVM as a delivery platform.
Why do I get UnsupportedClassVersionError?
Because the class file was compiled by a newer JDK than the JVM trying to run it. Every class file records a major version — Java 21 emits 65 — and a JVM refuses any file whose version it does not support rather than guessing. A JDK 21 JVM accepts 45 through 65.
Is the JVM part of the JRE, or the JRE part of the JVM?
The JVM is inside the JRE. The JRE is the JVM plus the standard class library, and the JDK is the JRE plus the development tools. Reading the containment in the wrong direction is the most common way this question is answered badly in interviews.
If Oracle no longer ships a JRE, what do I put in a container image?
A runtime image you build yourself with jlink, which assembles only the modules your application needs. A java.base-only image measures 52 MB against 295 MB for the full JDK. Some distributions, Eclipse Temurin among them, do still publish a standalone JRE if you would rather download one.

References

  1. The Java Virtual Machine Specification, Java SE 21 — IntroductionOracle
  2. The Java Virtual Machine Specification, Java SE 21 — The class File FormatOracle
  3. java — the Java launcher (JDK 21 tool specification)Oracle
  4. javac — the Java compiler (JDK 21 tool specification)Oracle
  5. javap — the class file disassembler (JDK 21 tool specification)Oracle
  6. jlink — the Java linker (JDK 21 tool specification)Oracle
  7. java.base module summary (Java SE 21 API)Oracle
  8. UnsupportedClassVersionError (Java SE 21 API)Oracle
  9. JEP 220: Modular Run-Time ImagesOpenJDK
  10. JEP 282: jlink — The Java LinkerOpenJDK
  11. JEP 330: Launch Single-File Source-Code ProgramsOpenJDK
  12. JDK 11 Release Notes — removed features and optionsOracle
  13. Eclipse Temurin releasesEclipse Adoptium