Command Palette

Search for a command to run...

PHASE 0Beginner ~30 min· topic 2 of 8

Topic 0.2

What Java Is: JDK, JRE, JVM and Bytecode

In one line

Java is a programming language plus a platform to run it. The javac compiler turns your .java files into portable bytecode (.class files), and a Java Virtual Machine on each computer runs that same bytecode, which is why one compiled program works on Windows, macOS and Linux. The JDK is the toolbox for writing Java; the JVM is the engine that runs it.

Think of it like this

Sheet music. A composer writes a song once, as sheet music. A pianist in India, Brazil or Japan can play it, because every pianist knows how to read sheet music and turn it into sound on their own piano. In Java, your program is compiled once into bytecode (the sheet music), and every computer has a Java Virtual Machine (the pianist) that knows how to play bytecode on its own kind of chip.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Compiler
A program that translates your whole source code into another form before it runs. Java's compiler is javac.
Bytecode
The instructions inside a .class file. They are written for the JVM, not for a real chip, so the same file runs on any computer with a JVM.
Class file
The file javac produces from your source, such as Main.class. One is made for every class in your code.
JVM
Java Virtual Machine: the program that loads and runs bytecode on a real computer. You start it with the java command.
JDK
Java Development Kit: everything you install to write and run Java, including javac, java, jshell and the standard library.
JRE
Java Runtime Environment: the JVM plus the standard library, without the developer tools. Older Java versions shipped it separately.
Standard library
Thousands of ready-made classes that come with Java, such as String, Math and ArrayList, so you don't write everything yourself.
Platform independent
Works on any operating system and chip. Java bytecode is platform independent; each JVM is built for one platform.
Garbage collector
The part of the JVM that automatically frees memory used by objects your program no longer needs.
Distribution
A ready-to-install JDK built from OpenJDK by a vendor, such as Eclipse Temurin or Amazon Corretto.

Step by step

01Two jobs: translate, then run

Running Java is a two-step job, done by two different programs. First the compiler javac translates your source into bytecode and saves it as a .class file. Second, the JVM (started with java) runs that bytecode.

You can compile on a Windows laptop, copy Main.class to a Linux server and a Mac, and run it on all three without compiling again. Each machine needs its own JVM, but the class file is the same.

Two jobs: translate, then rundiagram
Rendering diagram…

02What the compiler checks and produces

javac does more than translate. It reads the whole file and checks Java's rules: every statement is well formed, every name you use exists, and every value has the right type (you can't store text in a number box). If anything is wrong, it prints errors and produces no class file. That is why many Java mistakes are caught before the program ever runs.

If everything is fine, it writes one .class file per class. A source file with two classes produces two class files.

Main.javawhole filejava
class Greeter {
    String greet(String name) {
        return "Hello, " + name + "!";
    }
}

public class Main {
    public static void main(String[] args) {
        Greeter g = new Greeter();
        System.out.println(g.greet("Asha"));
    }
}
terminal
$ javac Main.java
ls
── expected output ──
Greeter.class Main.class Main.java

03Peek inside a class file with javap

Bytecode is not secret. The JDK tool javap -c prints it in a readable form. Below is a small method add(int x, int y) { return x + y; } after compilation. The JVM is a stack machine: instructions push values onto a small work pile called the operand stack, and other instructions pop them off and work on them.

iload_0 pushes the first argument, iload_1 pushes the second, iadd pops both and pushes their sum, ireturn returns the top value. The i means "int". You will never write bytecode by hand, but knowing it exists explains how Java runs (Topic 0.8).

terminal
$ javap -c Main
── expected output ──
static int add(int, int);
Code:
0: iload_0
1: iload_1
2: iadd
3: ireturn

04The JVM: a pretend computer inside your real one

The word virtual means "not physical, made in software". The JVM is a program written mostly in C++ that behaves like a computer whose machine code is bytecode. When you type java Main, the operating system starts the JVM, and the JVM then loads Main.class and runs its main method.

Because every JVM obeys the same written rules (the Java Virtual Machine Specification), the same bytecode gives the same results everywhere. int is always 32 bits, 0.1 + 0.2 prints the same digits on every machine, and the order of evaluation is fixed. The first runnable example below shows numbers that are identical on any JVM.

05JDK, JRE, JVM: boxes inside boxes

Picture three nested boxes. The innermost is the JVM, the engine that runs bytecode. Around it is the JRE, which adds the standard library the engine needs (String, Math, collections, files). Around that is the JDK, which adds the developer tools (javac, jshell, javap, jar...).

To run Java programs you need at least a runtime. To write them you need the JDK. Today you install a JDK either way. For servers, teams often use jlink to build a slim runtime containing only the parts their app uses.

JDK, JRE, JVM: boxes inside boxesdiagram
Rendering diagram…

06One language, many distributions

Java is developed in the open as OpenJDK. Vendors build it, test it, and publish installers: Eclipse Temurin (from the Adoptium group), Oracle JDK, Amazon Corretto, Azul Zulu, Microsoft Build of OpenJDK, Red Hat build of OpenJDK and others. They differ in support offerings and licences, not in the language.

The engine inside nearly all of them is HotSpot, the JVM that started at Sun Microsystems. Other JVMs exist, such as Eclipse OpenJ9 and GraalVM, and all of them must pass the official compatibility tests to call themselves Java.

07Java is not JavaScript

Java (1995, Sun Microsystems) and JavaScript (1995, Netscape) share part of a name because of a marketing deal, and they both use curly braces. That is where the similarity ends. JavaScript usually runs inside web browsers and checks types while the program runs. Java runs on the JVM and checks types before the program runs.

If you search the web for help, include the word "Java" and not "JS", or you'll get answers for the wrong language.

Try it yourself

  1. 1

    Find the class files

    On your own machine (after Topic 0.4), save the first example as Main.java, run javac Main.java, and list the folder. You should see Main.class and Greeter.class. Delete Greeter.class and run java Main: the JVM fails with NoClassDefFoundError: Greeter, because it loads classes from files when they are first needed.

    terminal
    $ javac Main.java
    java Main
    ── expected output ──
    Hello, Asha!
    Hello, Ben!
    This file compiled into Main.class and Greeter.class.
  2. 2

    Read your own bytecode

    Run javap -c Main on the class you just compiled. Find invokevirtual lines: each one is a method call. Find ldc lines: each loads a constant, such as your text "Hello, ".

  3. 3

    Predict the overflow

    In the second example, change Integer.MAX_VALUE + 1 to Integer.MAX_VALUE + 2. Predict the output before you run it. (It is -2147483647: the value wraps around like a car's odometer. Topic 1.3 explains why.)

Code & diagrams

Two classes, one file, two class files New tab

javac writes Greeter.class and Main.class. The JVM loads Greeter only when main first uses it.

Sign in to run this example in your browser.

Expected output

Hello, Asha!
Hello, Ben!
This file compiled into Main.class and Greeter.class.
The same answers on every JVM New tab

The Java specification fixes the size of int and the rules of arithmetic, so these lines print exactly the same on Windows, macOS, Linux and in the browser.

Sign in to run this example in your browser.

Expected output

Biggest int: 2147483647
Biggest int + 1: -2147483648
0.1 + 0.2 = 0.30000000000000004
7 / 2 = 3
An int uses 4 bytes
Using the standard library New tab

Math, String and List come with every JDK. You didn't write them, and you don't install anything extra to use them.

Sign in to run this example in your browser.

Expected output

Square root of 81: 9.0
Bigger of 7 and 12: 12
Shout: JAVA
Fruits: [mango, apple]
Bytecode for a whole program (javap -c)text

Real output of `javap -c Main` (JDK 21) for a program whose main adds two ints with add(a, b) and prints "Sum: " + sum. The constructor part is left out.

  public static void main(java.lang.String[]);
    Code:
       0: iconst_2
       1: istore_1
       2: iconst_3
       3: istore_2
       4: iload_1
       5: iload_2
       6: invokestatic  #7                  // Method add:(II)I
       9: istore_3
      10: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
      13: iload_3
      14: invokedynamic #19,  0             // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;
      19: invokevirtual #23                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      22: return

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Run a class file that is newer than your JVM

Compile with JDK 21 (javac Main.java), then run the class with an old Java 8 runtime.

terminal
$ java Main
── what you'll see ──
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.UnsupportedClassVersionError: Main has been compiled by a more recent version of the Java Runtime (class file version 65.0), this version of the Java Runtime only recognizes class file versions up to 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
...

Myth vs fact

Myth

Java is slow because it is interpreted.

Fact

The JVM interprets bytecode only at first. Code that runs often is compiled to optimised machine code by the JIT compiler, and long-running Java services often match C++ speed for typical server work. Start-up is slower, which is a separate issue (Topic 0.8).

Myth

Java and JavaScript are the same language, or one is a lighter version of the other.

Fact

They are unrelated languages that share a name for historical marketing reasons.

Myth

I need to install a JRE to run Java and a JDK to write it.

Fact

Modern Java is installed as a JDK. It runs programs too. Separate JRE downloads stopped with Java 11; apps that need a small runtime build one with jlink.

Myth

Write once, run anywhere means my program behaves identically everywhere, no matter what.

Fact

The language and bytecode behave identically. Things outside the JVM still differ: file paths (C:\Users vs /home), line endings, installed fonts, default character encoding before Java 18, and the time zone. Good Java code avoids relying on them.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Every class file starts with the magic bytes 0xCAFEBABE, then a minor and major version. Major version = Java version + 44, so Java 8 is 52, Java 11 is 55, Java 17 is 61, Java 21 is 65 and Java 25 is 69. javap -v Main | grep major shows it.

  • ▸

    Bytecode is typed and stack-based, about 200 opcodes. Since Java 7 there is invokedynamic, which lets the JVM link a call site at run time. javac uses it for lambdas (Java 8) and, since Java 9, for string concatenation (makeConcatWithConstants in the javap output above) so the JVM can pick the fastest strategy without recompiling your code.

  • ▸

    JDK vs JRE matters in containers: a full JDK image is several hundred megabytes. jdeps --print-module-deps finds the modules your app uses, and jlink --add-modules ... --output rt builds a runtime with only those, often under 60 MB (see the Docker course for multi-stage builds).

  • ▸

    The JVM is a specification (JVMS) with several implementations. HotSpot is the default in OpenJDK builds; OpenJ9 trades some peak speed for lower memory; GraalVM adds the Graal JIT and Native Image, which compiles ahead of time to a standalone executable with fast start-up but a closed-world limit on reflection.

Remember this

  1. 1

    Java is two things. Java the language is the set of words and grammar rules you write (class, if, int...), defined by the Java Language Specification. Java the platform is everything that runs your code: the JVM plus a large standard library of ready-made code for text, maths, files, networking, collections and more.

  2. 2

    The compiler javac reads your source file Main.java, checks it against the language rules, and writes Main.class. That file holds bytecode: compact instructions for an imaginary computer, the same on every operating system. It is not machine code for your real CPU.

  3. 3

    The JVM (Java Virtual Machine) is a program that pretends to be that imaginary computer. You start it with the java command. It loads .class files, checks them for safety, runs the bytecode, and translates frequently used parts into real machine code for the CPU it is on (Topic 0.8). There is a different JVM build for each operating system and chip, but they all run the same bytecode. This is Java's famous promise: write once, run anywhere.

  4. 4

    The JDK (Java Development Kit) is what you install to write Java. It contains a JVM, the standard library, and the developer tools: javac (compiler), java (launcher), jshell (try code interactively, Topic 0.6), jar (package classes), javadoc (documentation), javap (look inside class files) and diagnostic tools such as jcmd. The JRE (Java Runtime Environment) was the smaller package with only the JVM and library, for people who just run Java programs. Since Java 11 no separate JRE is published by Oracle; you install a JDK, or build a trimmed runtime for your app with jlink.

  5. 5

    The JVM manages memory for you. When you create objects, the JVM finds space for them, and a garbage collector frees that space once nothing uses the objects any more. You never free memory by hand, which removes a whole family of crashes common in languages like C. You'll see how in Topic 3.11 (stack and heap) and Topic 14.3 (garbage collection).

  6. 6

    OpenJDK is the open-source project where Java itself is built. Companies take its code and publish ready-to-install JDKs called distributions: Eclipse Temurin, Oracle JDK, Amazon Corretto, Azul Zulu, Microsoft Build of OpenJDK and others. They are built from almost the same source and behave the same for your programs. This course recommends Eclipse Temurin because it is free and open source (Topic 0.4).

  7. 7

    Java is not JavaScript. The names are similar for marketing reasons from 1995, but they are different languages with different rules. Java is statically typed (every variable has a fixed type checked before the program runs), object-oriented (programs are built from classes and objects, Phase 4) and garbage-collected. It runs banking systems, Android apps (through Android's own runtime), big-data tools like Kafka and Hadoop, and games like Minecraft: Java Edition.

Explain it without notes

01

Explain the difference between the JDK, the JRE and the JVM.

02

What is bytecode, and why doesn't Java compile straight to machine code?

03

How does Java achieve "write once, run anywhere", and where does that promise stop?

04

What is OpenJDK, and why are there several JDK distributions?

Practice

01

Write a program with two classes in one file: a Calculator class with a method that doubles a number, and Main, which prints the double of 21.

02

Write a program that uses Math.max, Math.min and Math.abs from the standard library and prints the results for 8 and -3.

03

Write a program that prints Integer.MAX_VALUE and Long.MAX_VALUE, each on its own line.

Trade-offs

  • ↔

    Bytecode plus a JVM buys portability, safety checks and run-time optimisation, at the cost of start-up time and memory for the JVM itself. Ahead-of-time compilation (GraalVM Native Image) flips that trade: fast start, small memory, but a longer build and limits on dynamic features.

  • ↔

    Automatic garbage collection removes whole classes of memory bugs, but the collector uses CPU and can pause the program briefly. Modern collectors (G1, ZGC) keep pauses short; Topic 14.3 covers tuning.

  • ↔

    Picking a distribution is about support, not features: a vendor with long-term updates for your Java version matters more than the brand name.

Done when you can

  • Done when you can explain JDK, JRE and JVM with the nested-boxes picture.

  • Done when you can say what javac produces and what the java command does with it.

  • Done when you can explain bytecode with the sheet-music analogy and say why it makes Java portable.

  • Done when you can name two JDK distributions and say why they behave the same.

  • Done when you can explain why a class compiled with Java 21 fails on Java 8.