Java Compilation and Execution Process

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 public or System.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 HelloWorld goes in HelloWorld.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.

Terminal window
javac HelloWorld.java # βœ… reads HelloWorld.java and creates HelloWorld.class

You 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 .class file, 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 .class file, 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.

Terminal window
java HelloWorld # βœ… JVM loads HelloWorld.class and runs the bytecode

Notice 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.class and 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.

HelloWorld.java (your code)

javac (compiler)

HelloWorld.class (bytecode)

JVM (loads, verifies, runs)

Hello, World! (output)

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 .java file instead of the class.

    Terminal window
    java HelloWorld.java # ❌ tries to run source, often confusing on older setups
    java HelloWorld # βœ… runs the compiled class

    You compile the .java file, then run the class by its name.

  • Adding .class to the run command.

    Terminal window
    java HelloWorld.class # ❌ the JVM looks for a class literally named HelloWorld.class
    java HelloWorld # βœ… pass only the class name

    The JVM adds the .class part 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 be HelloWorld.java. A mismatch makes javac complain 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.class exists 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 .class file.
  • Read compile errors top to bottom. javac reports the first real problem first. Fix it, then recompile. Later errors are often side effects.
  • Recompile after every change. A .class file is a snapshot. Forget javac and you keep running the old version.
  • Check your tools with javac -version and java -version. A missing javac means 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 .java source file in plain, human-readable Java.
  • βœ… javac checks your code and turns it into .class bytecode.
  • βœ… 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 β†’ .class bytecode β†’ 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. 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. 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. 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. 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.

JVM Architecture in Java

Share & Connect