Unit 01 · lesson

Source Code Is Not the Program the JVM Executes

When you write Java, you create source code. The Java Virtual Machine does not directly execute that source text.

A useful first model is:

Concept flow

Java source crosses two execution boundaries

Compilation and runtime are different stages, and each produces different evidence.

  1. SOURCEJava source expresses programmer intent
    compile
  2. COMPILERchecks syntax and type rules
    emit
  3. BYTECODE.class representation for the JVM
    execute
  4. JVMruns accepted bytecode
    observe
  5. BEHAVIORoutput, state changes, exceptions, or wrong results

That model is simple, but it explains a surprising amount of Java.

What the compiler does

A compiler checks whether your source follows the rules of the language and translates accepted code into another representation. In normal Java project work, javac produces .class files containing JVM bytecode.

The compiler is not asking, "Did the programmer mean something reasonable?" It is asking whether the program is structurally valid Java and whether required type relationships make sense.

Consider:

void main() {
    int students = 24;
    IO.println(students);
}

students is declared as an int. The value 24 fits that type. IO.println can print it. The program can move past compilation.

Now change one line:

int students = "twenty-four";

A human understands the idea. Java does not silently convert the text into an integer. The source violates the declared type relationship, so compilation stops.

That is a compile-time failure. The JVM never gets a runnable version of this program.

What the JVM does

The Java Virtual Machine executes Java bytecode and provides the runtime environment used by the program.

This separation is part of Java's portability model. Your source is not rewritten separately for every application you create. Java compilers produce bytecode defined for the JVM, and JVM implementations provide the platform-specific runtime work.

Do not turn "write once, run anywhere" into a magical claim that all systems behave identically. Programs still interact with operating systems, files, networks, fonts, time zones, native libraries, memory limits, and other environment-specific details. The JVM creates an important portability layer; it does not erase the environment.

Three different places a program can fail

Start separating failures now.

1. Before execution

void main() {
    int count = "5";
}

The compiler rejects the type mismatch.

2. During execution

void main() {
    int zero = 0;
    IO.println(10 / zero);
}

This can compile because division is valid for integers. At runtime, dividing an integer by zero causes an exception.

3. The program runs but is wrong

void main() {
    int width = 5;
    int height = 4;
    int area = width + height;
    IO.println(area);
}

The code is legal. It runs. It prints 9. But the formula for rectangular area should multiply width and height. This is a logic error.

That third category is why a green Run button is weak evidence. Software can execute perfectly and still produce the wrong answer.

Trace the pipeline

For each case, identify the first stage where the problem becomes visible.

CaseSource valid?Compiles?Begins execution?Produces intended result?
missing closing brace????
integer division by zero????
area = width + height????
correct area formula????

Do not fill the table by guessing what the teacher wants. Explain one row using the source -> compiler -> JVM model.

Optional full-JDK evidence

If you have an approved Java 25 JDK environment, create Hello.java and compare these two workflows:

java Hello.java

and

javac Hello.java
java Hello

The first uses the source-code launcher. The second exposes compilation as a separate step.

Record what new file appears after javac. Do not submit a screenshot alone. Label what that file represents in the execution chain.

Evidence to keep

Create a one-page execution trace containing:

  1. one valid Java source snippet;
  2. an arrow diagram from source to observable output;
  3. one compile-time failure;
  4. one runtime failure;
  5. one logic error;
  6. one sentence explaining why "it ran" cannot prove correctness.

If you can classify those failures without relying on the exact error-message wording, you are already debugging at a more useful level than someone who only searches whatever red text appears first.