Java Compilation and Execution Process
Table of Contents + β
In the last lesson you learned about Java comments and Javadoc. Now letβs answer a bigger question: what actually happens between the moment you write code and the moment you see output?
You type Java in a file. You run a couple of commands. Something prints. But the middle feels like magic. By the end of this lesson the magic is gone.
π§© The big idea: compile, then run
Java works in two stages, not one:
- Compile. Turn your human-readable code into an in-between form called bytecode.
- Run. A program called the JVM takes that bytecode and runs it on your computer.
The journey is always the same shape. You write .java, the compiler makes .class bytecode, the JVM runs it, you get output. The key word is bytecode. It is the bridge between the code you write and the program that runs.
βοΈ Step 1: you write the .java source
It all starts with a plain text file ending in .java:
- It is for humans. Written in Java, close to English. You can read and edit it in any editor.
- The computer cannot run it directly. Your processor does not understand words like
publicorSystem.out.println, so this is a starting point, not a finished program. - The file name matters. A public class must live in a file with the exact same name. Class
HelloWorldgoes inHelloWorld.java.
Here is a tiny program saved in HelloWorld.java. It prints one line.
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); }}Right now this is only text on disk. Nothing runs yet. To make it do something, hand it to the compiler.
βοΈ Step 2: javac compiles it into bytecode
The compiler is called javac (βJava compilerβ). It ships with the JDK. You point it at your source file, and this command compiles our example.
javac HelloWorld.java # β
reads HelloWorld.java and creates HelloWorld.classYou now have a new file next to your source: HelloWorld.class. Here is what javac did:
- Checked your code. A missing semicolon or typo stops it and prints an error now, before the program ever runs.
- Translated your code. Your Java text becomes bytecode.
- Saved the result. The bytecode goes into the
.classfile, ready for the next step.
Compile errors happen here
If javac prints errors, no .class file is made, or an old one stays unchanged. So always fix compile errors first. A program cannot run if it never compiled.
π¦ What is bytecode, and why is it portable?
Inside the .class file is bytecode: simple instructions made for the JVM, not for any one real chip. It is a halfway language between the Java you write and the raw zeros and ones a chip understands. That middle position earns Java its famous promise, write once, run anywhere:
- It does not target a real chip. Windows and Mac processors speak different native languages. Bytecode speaks neither. It speaks βJVMβ.
- Every system has its own JVM. Windows, Mac, and Linux each have a JVM that turns the same bytecode into instructions for its own machine.
- One build runs everywhere. Compile once into a
.classfile, copy it to any machine with a JVM, and it runs. No recompiling per operating system.
Compare this to C, where you build a separate program for each kind of machine. Java skips that by stopping at bytecode and letting the local JVM finish the job.
A real-life way to see it
Bytecode is like a music file. The same song file plays on a phone, a laptop, or a speaker. Each device has its own player that knows its own hardware. You make one song, not one per device. The JVM is that player for your code.
π Step 3: the JVM loads and runs the bytecode
You start the JVM with the java command. This runs our example.
java HelloWorld # β
JVM loads HelloWorld.class and runs the bytecodeNotice itβs java HelloWorld, not java HelloWorld.class. You pass the class name and the JVM finds the matching file. Then it works in a few steps:
- Loads the bytecode. Finds
HelloWorld.classand reads it into memory. - Verifies the bytecode. Checks it is safe and well-formed first, so broken or harmful code cannot hurt your machine.
- Runs the bytecode. An interpreter carries out the instructions one by one.
- Speeds up hot code. The JIT (Just-In-Time compiler) turns often-used parts into fast native machine code while the program runs, so Java ends up close to native speed.
The result is your output. The JVM reaches the print instruction and shows one line.
Output
Hello, World!π The whole journey in one picture
Here is every step together, from the file you write to the output on screen.
The path is short and always the same: .java β javac β .class bytecode β JVM β output.
Why split it into two steps? The split is what gives you portability. Compile once, and the bytecode is the same everywhere. The run step happens on each machine, where the local JVM fits that bytecode to the hardware. One write, one compile, many machines.
β οΈ Common Mistakes
These slip-ups produce confusing errors. Knowing them now saves time.
-
Trying to run the
.javafile instead of the class.Terminal window java HelloWorld.java # β tries to run source, often confusing on older setupsjava HelloWorld # β runs the compiled classYou compile the
.javafile, then run the class by its name. -
Adding
.classto the run command.Terminal window java HelloWorld.class # β the JVM looks for a class literally named HelloWorld.classjava HelloWorld # β pass only the class nameThe JVM adds the
.classpart for you, so you must leave it off. -
Class name and file name do not match. If your class is
public class HelloWorld, the file must beHelloWorld.java. A mismatch makesjavaccomplain right away. Keep the names identical, including capital letters. -
βCould not find or load main classβ. This common error usually means you are in the wrong folder, you typed the name wrong, or you never compiled. Check that
HelloWorld.classexists in your current folder and that you spelled the name exactly. -
Thinking bytecode is machine code. Bytecode is the halfway form. It still needs the JVM to run. It is not the raw instructions your chip reads directly.
β Best Practices
A few habits that keep this smooth from day one:
- Match the file name to the public class name. Same word, same capital letters. Avoids a whole family of errors.
- Compile and run from the folder that holds your files. Then the JVM can find the
.classfile. - Read compile errors top to bottom.
javacreports the first real problem first. Fix it, then recompile. Later errors are often side effects. - Recompile after every change. A
.classfile is a snapshot. Forgetjavacand you keep running the old version. - Check your tools with
javac -versionandjava -version. A missingjavacmeans you have a runtime only, not the full JDK.
π§© What Youβve Learned
The journey from code to output:
- β Java works in two stages: compile first, then run.
- β
You write a
.javasource file in plain, human-readable Java. - β
javacchecks your code and turns it into.classbytecode. - β Bytecode is a halfway form made for the JVM, not for any one real chip, which is what makes it portable.
- β The JVM loads, verifies, and runs the bytecode, using an interpreter plus the JIT for speed.
- β
The full flow is
.javaβjavacβ.classbytecode β JVM β output. - β This split is what gives Java its βwrite once, run anywhereβ promise.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does the javac compiler produce from a .java file?
Why: javac reads your .java source and creates a .class file that holds bytecode, the in-between form the JVM runs.
- 2
Why is Java bytecode portable across different operating systems?
Why: Bytecode speaks 'JVM', not the native language of one chip. Each operating system has its own JVM that runs the same bytecode, so one build runs everywhere.
- 3
Which command correctly runs a compiled class called HelloWorld?
Why: You pass the class name only. The JVM finds the matching HelloWorld.class for you, so you leave off the .class part.
- 4
A public class is named HelloWorld. What must the source file be named?
Why: A public class must live in a file with the exact same name, including capital letters, so it must be HelloWorld.java.
π Whatβs Next?
You now know the full path from code to output, and where the JVM fits in. Next we look inside the JVM that runs your bytecode, so you can see how it loads, verifies, and runs your program from the inside.