How Java Code Runs

From Source Code to Output

Main.java  --javac-->  Main.class  --java-->   JVM  --->  Output
 (source)   (compiler)  (bytecode)  (launcher)   |
                                                  +-- Class Loader  (loads .class files)
                                                  +-- Bytecode Verifier (safety checks)
                                                  +-- Interpreter + JIT (runs, compiles hot code)
                                                  +-- Garbage Collector (frees memory)

Step by Step

  1. Write source code in a .java file.
  2. Compile: javac checks syntax and types and produces bytecode in a .class file. Bytecode is not machine code for any real CPU; it is code for the JVM.
  3. Load: the JVM class loader reads the .class file.
  4. Verify: the bytecode verifier checks that the code is safe.
  5. Execute: the interpreter runs the bytecode. Code that runs often ("hot" code) is compiled to fast native machine code by the JIT (Just-In-Time) compiler.

Compile-time vs Runtime Errors

Some mistakes are caught by javac before the program runs (compile-time errors), others only appear while the program runs (runtime errors / exceptions).

int age = "twenty";   // compile-time error: incompatible types: String cannot be converted to int

Example

This program compiles fine, but dividing an integer by zero fails at runtime:

public class Main {
    public static void main(String[] args) {
        int total = 100;
        int people = 0;
        System.out.println("Splitting the bill...");
        System.out.println(total / people);
    }
}

Output

Splitting the bill...
Exception: java.lang.ArithmeticException: / by zero

Tip: Compile-time errors are your friend: Java finds many bugs before the code ever reaches users.