Home › Guides › Java
Java8 min readCode verified

What Actually Happens When You Compile and Run Java

Two commands, two tools, and two completely different kinds of error. Once you can tell which one is talking to you, most beginner Java problems name themselves.

Sheet music, and the musician#

You have a tune in your head. You want people in other countries to be able to play it.

You do not post them a recording, because a recording only plays on the machine it was made for. You write the tune out as sheet music. Sheet music is exact: every note, every rest, no room for interpretation about which note comes next. It is also completely silent. A page of music makes no sound at all.

It makes sound when a musician reads it. Any musician, anywhere, on any instrument they happen to own. The sheet never changes; the musician is the part that differs from place to place.

That is Java, exactly. You write the tune. One tool turns it into sheet music. A second tool is the musician who reads that sheet and plays it, and there is a different musician installed on Windows, on macOS and on Linux. Write once, and it plays anywhere someone has a musician.

What file appears?#

javac Hello.java

That command finishes without printing anything. What file did it create, and can you double-click it to run your program? Answer both before reading on.

The common answer is an .exe, or something like it — a finished program you can hand to someone. That is what compiling means in most languages people have heard of.

Java makes Hello.class, and no, you cannot double-click it. Nothing on your computer knows how to run it directly.

The file holds bytecode: instructions for a machine that does not physically exist. To run it we start that machine — the Java Virtual Machine — and hand it the file. That is the second command, and it is why Java compiles once and runs on Windows, macOS and Linux without being rebuilt.

The short answer#

Running a Java program takes two commands, and they are run by two different programs:

javac Hello.java     // compile: source  -> bytecode
java Hello           // run:     bytecode -> output

Read the two lines out loud and mind the endings, because that is where the mistake lives. The first is “javac, Hello dot java” — you hand the compiler a file, so it gets the file’s full name. The second is “java, Hello” — you hand the launcher a class name, not a file, so there is no .java and no .class on the end. Typing java Hello.class is one of the first errors nearly everyone hits.

javac is the compiler. It reads the text you wrote and, if the text is legal Java, writes a new file called Hello.class. java is the launcher. It starts the Java Virtual Machine and executes that .class file.

The distinction that matters all semester

if javac complains, your program never ran at all — there is nothing to run. If java complains, your program compiled fine and then went wrong while executing. Those are compile-time and run-time errors, and they are fixed in completely different ways.

Step 1 — javac turns source into bytecode#

Start with one file, Hello.java:

Hello.java
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

Before compiling, the directory holds one file. After javac Hello.java, it holds two:

Hello.java     119 bytes    your source
Hello.class    417 bytes    produced by javac

The .class file is bytecode. It is not the text you wrote, and it is also not machine code for your particular processor. It is an instruction set for an imaginary computer — the JVM — which every real machine then emulates.

You can see that it is a real, structured binary format, not compressed text. Every .class file ever produced begins with the same four bytes:

ca fe ba be 00 00 00 41

Those first four bytes spell CAFEBABE — the format's magic number, a joke that has been in the file format since 1995. The 41 at the end is hexadecimal for 65, the class-file version written by Java 21.

Step 2 — java runs the bytecode#

Now the second command. Note carefully what you hand it:

java Hello
Hello, world!

You passed Hello, not Hello.class and not Hello.java. The launcher wants a class name, and it works out the filename itself. Typing the extension is probably the single most common first-day error:

$ java Hello.class
Error: Could not find or load main class Hello.class
Caused by: java.lang.ClassNotFoundException: Hello.class

Read that message literally and it makes sense: it went looking for a class named Hello.class, and there is no such class.

Why bother with two steps?#

Languages like C compile straight to machine code for one kind of processor, so a program built for Windows will not run on a Mac. Languages like Python skip compilation and interpret the source line by line every time, which costs speed.

Java splits the difference. javac does the expensive analysis once and produces bytecode that is not tied to any processor. Any machine with a JVM can then run that same .class file unchanged. This is what the old slogan write once, run anywhere is describing — the portable artifact is the compiled .class file, not the source.

The five errors you will actually hit first#

These are worth reading now, because you will meet all five, and each one is easier to fix when you recognize the wording.

1. The file name does not match the public class#

Saving public class Hello into a file called Greeter.java:

Greeter.java:1: error: class Hello is public, should be declared in a file named Hello.java
public class Hello {
       ^
1 error

A public class must live in a file of exactly the same name, capital letters included. Rename one or the other.

2. A missing semicolon#

Semi.java:3: error: ';' expected
        System.out.println("hi")
                                ^
1 error

Notice where the caret points: at the end of line 3, not at line 4. The compiler reports the position where the missing thing should have been, which is why a missing semicolon is often reported on the line above the one that looks wrong.

3. No main method#

This one compiles perfectly and then fails at run time — a class with no main is legal Java, it just cannot be used as a starting point:

Error: Main method not found in class NoMain, please define the main method as:
   public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application

4. main exists but is not static#

Error: Main method is not static in class Inst, please define the main method as:
   public static void main(String[] args)

The JVM has to call main before any object exists, so it can only call a method that belongs to the class itself. That is what static means here.

5. main returns something#

In C a program's entry point returns an int. In Java it does not, and the JVM says so plainly:

Error: Main method must return a value of type void in class IntMain, please
define the main method as:
   public static void main(String[] args)

Compile-time or run-time?#

Sort every error you meet into one of these two columns and the fix usually suggests itself.

Compile-time errorRun-time error
Reported byjavacjava (the JVM)
Looks likeFile.java:3: error: ... with a line number and a caretError: ... or Exception in thread "main" ...
Did the program run?No. No .class file was produced.Yes, and it may have already printed output before failing.
Typical causeTypo, missing semicolon, wrong type, misspelled methodMissing main, bad input, dividing by zero, wrong command

Where these go wrong#

  • Editing and re-running without recompiling. java reads the .class file, so until you run javac again you are still running yesterday's program. If a change appears to have no effect at all, check this first.
  • Typing java Hello.class. The launcher takes a class name. No extension, ever.
  • Fixing errors from the bottom up. One real mistake often produces several complaints. Fix the first error, recompile, and watch most of the rest disappear.
  • Assuming a compile error means the program crashed. It never even started. There is no output to look for and no .class file to run.
  • Case. Hello.java and hello.java are different files, and Hello and hello are different classes. Windows will sometimes let you get away with this locally and then it breaks elsewhere.
One sentence to carry into the exam

Two commands, two kinds of error. javac makes the sheet music and complains about how you wrote it. java is the musician and complains about playing it. Knowing which one failed tells you where to look before you read a single line.

Test yourself in the free Kestrel Exams app

Topic-selectable practice — offline, no ads, no account.

Practice this topic →

Frequently asked questions#

Do I need to compile Java every time I change the code?

Yes. javac reads your .java source and writes a .class file; the java command only ever runs the .class file. If you edit the source and re-run without recompiling, the JVM happily runs the previous version, which is a common and very confusing way to lose ten minutes.

What is the difference between javac and java?

javac is the compiler: it turns human-readable source into bytecode and reports syntax and type errors. java is the launcher: it starts the Java Virtual Machine and executes bytecode that already compiled successfully. Errors from javac are compile-time errors; errors from java are run-time errors.

Why does my file have to be named after the class?

Java requires a public class to live in a file of exactly the same name, because that is how the compiler and the class loader find it later. Putting public class Hello in Greeter.java gives the error: class Hello is public, should be declared in a file named Hello.java.

Why do I get “Could not find or load main class”?

Most often because the .class extension was typed on the run command. The java launcher takes a class name, not a filename, so it is java Hello and never java Hello.class. The same message also appears when you run from the wrong directory.

What is bytecode?

Bytecode is the compact instruction set inside a .class file. It is not the source you wrote and not machine code for your specific processor — it is an intermediate form that any Java Virtual Machine can execute, which is what lets the same compiled file run unchanged on Windows, macOS and Linux.

Suggest a change

Something here not clear? A topic you wish we covered? Tell us. We read every message, and a request is the fastest way to get a guide written — several of these exist because somebody asked.