Dev Learning Lab

The labs on this site need JavaScript to run. The same content is written out below.

Fundamentals › Java

Compilation and the JVM

How does Java code run?

The Hello.java file that we write is text for people to read. When you run it with java Hello, this text is not run as it is, but goes through two steps. When you use the command javac Hello.java in a terminal (a window where you type commands as text), a program called javac (the compiler) reads this text and turns it into a file named Hello.class. This job is called compiling. Hello.class contains bytecode, which the JVM reads. Next, when you use the command java Hello, the JVM (Java Virtual Machine) starts, reads Hello.class, and runs main. In this lab you remove the javac line, make the source text wrong, or edit it after compiling, and the real javac and java commands are run, to show whether Hello.class is created and what java Hello runs.

Checked against real execution · Ran the javac and java commands of JDK 21 for real in 6 combinations and checked the results against them

Concepts in this lab

Compilation and javac
Compilation is the job of turning source code written by a person into a form that the JVM can run, and in Java the program that does this job is javac (the Java compiler). The javac command reads source files with the extension .java and turns them into class files with the extension .class, and if nothing else is set it creates the class files in the same folder as the source files. javac only converts the code and does not run it, so running on the JVM is a separate step after compiling. If the source has an error, javac prints an error message, and if there are no errors, the class files are placed in the output folder. Even if you edit the source file, the class file you already made does not change, so to use the edited code you have to compile again with javac.
Class file
A .class file is a file created as the result of compiling, in the class file format that the JVM reads. It contains JVM instructions (bytecode), a symbol table, and other additional information, and the first 4 bytes of the file are 0xCAFEBABE, which marks this format. The JVM does not know the Java language and knows only this class file format. When you run by class name, as in java Hello, the JVM looks for the class of that name on the class path, and if you do not set the class path, it is the current folder. So even if Hello.java is in the same folder, if there is no Hello.class you get an error that the class Hello cannot be found.
Java Virtual Machine (JVM)
This is the program that reads and runs Java bytecode. Each operating system has its own version of it, so a Java program that is compiled once can run on several operating systems without modification. It loads classes, manages memory (garbage collection), and converts bytecode to machine code and runs it.
Bytecode
This is the intermediate form of code that the Java compiler (javac) produces from source code, and it is stored in .class files. It is not the machine code of a particular CPU or operating system but a set of instructions that the JVM understands, so it runs on the JVM of any platform.

Try these

Running with the default settings

  1. The file Hello.java contains Java code that people read, and this code means to print "Hi". Running this code takes two steps. First, the javac command turns the file Hello.java into another file named Hello.class (compiling), and then the java command reads the file Hello.class and runs it. What the java command looks for is not the text in Hello.java but the file Hello.class.
  2. You run the command javac Hello.java in the terminal. The javac compiler reads the file Hello.java from the beginning and checks that it follows Java syntax, and if it does, it turns what it read into bytecode and writes it to the file Hello.class. This step only converts the code and does not run it, so nothing is printed.
  3. The javac command finished without errors (exit code 0). The file Hello.class now exists in the folder. This file contains not text for people to read but bytecode for the JVM to read. The file Hello.java remains as it was.
  4. You run the command java Hello in the terminal. The java command starts the JVM, and the JVM looks for the file Hello.class in the current folder and loads it. What the JVM reads is the file Hello.class, not the file Hello.java.
  5. The JVM runs main in Hello.class, and the println in main prints Hi.

Result of this run

Code

# Hello.java
public class Hello {
    // main: the method that the java command calls first
    public static void main(String[] args) {
        System.out.println("Hi");
    }
}

# Terminal
# Compile: javac reads Hello.java and creates Hello.class
javac Hello.java
# Run: java starts the JVM, which runs main in Hello.class
java Hello

Assumptions of this model

The compiler and runtime are JDK 21.0.12.1 (javac 21, java 21). All 6 combinations were checked against real runs: for each combination, the same text as the code on the screen (the # Hello.java section and the # Terminal section) was written in an empty folder, the source file and the commands were read from that text, and the real javac program and java program were started as processes and run. What was checked is whether Hello.class appeared in the folder, the exit code and standard output of javac, the first error message and the number of errors and the line of the error, the exit code, output, and error message of java, whether the edit leaves Hello.class unchanged, and the first four bytes of the Hello.class file (CAFEBABE) and its version (65, Java 21). That the "Bye" is printed when you use the javac command again after the edit was also checked by a separate run. The commands that were run differ from the screen in two ways. To read the output text and the error messages in the same way, options were added to javac and java that set the output encoding to UTF-8 and the message language to English (-Dstdout.encoding=UTF-8, -Duser.language=en, and so on). Without the options, on the PC used to write this lab (Korean Windows), the java Hello command gives the same error as a Korean message. I opened the documentation and checked it. I followed section 1.2 of the Java Virtual Machine Specification, Java SE 21 Edition (the JVM does not know the Java language and knows only the class file format, and a class file contains bytecode, which are JVM instructions), section 4.1 of the same specification (the magic value at the very beginning of a class file is 0xCAFEBABE, and the major version for Java SE 21 is 65; I read only part of this chapter), the JDK 21 documentation of the javac tool (it reads .java source files and compiles them into .class files, creates them in the same folder as the source if nothing else is set, and puts the class files in the output folder if there are no errors), and the documentation of the java tool (it starts a JVM, loads the specified class, and calls main, and if the class path is not set it is the current folder; I read only the first part and could not read the exit code section). That no Hello.class is created when there is an error, that the exit codes are 0 and 1, and the text of the error messages are not set by the documentation but were observed on this JDK. The code on the screen was cut down to the situation where the folder has only one file, Hello.java, and classes with a package, class path settings, jar files, and an IDE or build tool compiling for you are not covered. The way of running a source file directly, as in java Hello.java (source-file mode), is not used on the screen either. When I ran it on this JDK, it printed Hi without creating Hello.class (the java documentation also explains that it compiles the source in memory and runs it), and a source with a missing semicolon failed with the same compile error in this mode too. I also confirmed that if, after a successful compile, you change the source to something wrong and use the javac command again, you get an error but the old Hello.class stays in the folder and the java Hello command runs the old code, but the screen does not cover this. How the JVM loads Hello.class is covered in the in-depth lab "Class loading and initialization", and JIT, which recompiles bytecode into machine code, is covered in the in-depth lab "JIT warmup".

Previous lab: Thread pools · Next lab: File I/O

Concepts in this lab

What this lab shows

Settings

Code


      
    

Diagram

Run comparison

Try these