Skip to content

Lesson 01 · How a Java Program Is Structured & Run

Objectives

After this lesson you will be able to:

  • Explain how Java source becomes a running program, and the roles of the JDK, JRE, JVM,javac, and java.
  • Describe the anatomy of a source file and the "one public top-level type per file" rule.
  • Write a valid main method and recognize which signatures the JVM will and won't launch.
  • Use packages and imports (single-type, on-demand, static) correctly, and know what is imported automatically.
  • Compile and run a program from the command line, and launch a single-file source program with java Foo.java.

The big picture: source → bytecode → JVM

Java is compiled, then interpreted/JIT-compiled. You write source in .java files; the compiler javac turns each into a .class file containing platform-neutral bytecode; the JVM (Java Virtual Machine) loads and executes that bytecode, compiling hot paths to native code at runtime via the JIT compiler. Because the bytecode is platform-neutral, the same .class runs on any machine with a compatible JVM — write once, run anywhere.

Greeting.java  ──javac──▶  Greeting.class  ──java (JVM)──▶  running program
   (source)                  (bytecode)                        (native via JIT)

Three acronyms you must keep straight:

TermWhat it isContains
JVMThe runtime engine that executes bytecode.
JREJava Runtime Environment: everything needed to run Java.JVM + core libraries
JDKJava Development Kit: everything needed to develop Java.JRE + tools (javac, jar, jshell, …)

SDET note

"Write once, run anywhere" is exactly why JVM tooling (Selenium, RestAssured, JUnit) ships as portable .jars. Knowing the compile-vs-runtime split also explains a class of CI failures: code that compiles against one library version but meets a different one on the runtime classpath — a NoSuchMethodError at run time, not a compile error.

Anatomy of a source file

A minimal program:

java
package com.example.greet;   // 1. package declaration (optional, but at most one, and first)

import java.util.List;       // 2. imports (zero or more, after package, before types)

public class Greeting {      // 3. one or more top-level type declarations
    public static void main(String[] args) {
        System.out.println("Hello, Java 21");
    }
}

The ordering rule is strict: package (if any) → imports (if any) → type declarations. Anything out of order is a compile error.

A file may declare several top-level types, but:

  • At most one may be public.
  • If a type is public, the file name must match it exactly (GreetingGreeting.java).
java
// File: Greeting.java  ✅ public type matches file name
public class Greeting {}
class Helper {}          // non-public companion types are fine in the same file

Exam trap

public class Greeting {} saved in a file called Main.java does not compile. The exam loves mismatched file names and two public types in one file (also illegal).

The main method — your entry point

To be launchable, a class needs a main with a signature the JVM recognizes:

java
public static void main(String[] args) { }

What actually matters:

  • Must be public and static, return void, and be named main.
  • Must take a single String[] parameter. The parameter name is irrelevant (args, xyz, whatever).
  • String[] args, String args[], and varargs String... args are all accepted.
  • The order of public static doesn't matter (static public is fine). final is allowed too.

These all launch:

java
public static void main(String[] args) {}
static public void main(String[] args) {}
public static void main(String... args) {}
public static final void main(String[] xyz) {}

These compile but the JVM won't launch them as a program (you get Error: Main method not found or main method is not static):

java
public void main(String[] args) {}          // not static
public static void main(String args) {}      // not a String[]
public static int main(String[] args) {}     // wrong return type for launching
private static void main(String[] args) {}   // not public  (see note)

Gotcha

The exam may show a class whose main is subtly wrong (missing static, String instead of String[]). The class compiles fine — the failure is at launch time, not compile time. Read carefully which kind of error is being asked about.

args holds the command-line arguments after the class name. java Greeting a b c gives args = {"a", "b", "c"} (length 3) — the program name is not element 0 (a common trap for people coming from C).

Packages and imports

A package is a namespace (and maps to a directory). The declaration, if present, must be the first statement.

Imports let you refer to a type by its simple name instead of its fully qualified name.

java
import java.util.List;        // single-type import
import java.util.*;           // import-on-demand: all PUBLIC types in java.util
import static java.lang.Math.PI;   // static import of a member
import static java.lang.Math.*;    // static import on-demand

Key rules the exam tests:

  • java.lang is imported automaticallyString, System, Math, Integer, etc. need no import.
  • Types in the same package need no import of each other.
  • * is not recursive: import java.util.*; does not bring in java.util.concurrent.*.
  • An import is never required — you can always write the fully qualified name (java.util.List) inline instead.
  • If two on-demand imports both offer the same simple name (e.g. java.util.List and java.awt.List), using List is ambiguous → compile error. Resolve it with an explicit single-type import, which wins over on-demand.
What prints (or fails)? — package & import puzzle
java
import java.util.*;
import java.sql.*;

public class P {
    public static void main(String[] args) {
        Date d = new Date();      // ❓
        System.out.println(d);
    }
}

Answer: It does not compile. Date exists in both java.util and java.sql, so the on-demand imports make the simple name Date ambiguous. Fix it with a single-type import, e.g. import java.util.Date;, which takes precedence.

Compiling and running from the command line

The classic two-step:

bash
javac Greeting.java        # produces Greeting.class
java Greeting              # runs it (note: no .class extension)

With packages, the package maps to a directory, and you run with the fully qualified name:

bash
# File at com/example/greet/Greeting.java  declaring  package com.example.greet;
javac com/example/greet/Greeting.java
java com.example.greet.Greeting        # FQCN, dot-separated, no .class

A frequent mistake: running java Greeting.class. You pass the class name, not the file — the launcher appends .class and searches the classpath for it.

Single-file source-code programs (Java 11+)

Since Java 11 you can run a source file directly, skipping the explicit javac step — handy for scripts, demos, and exam questions:

bash
java Greeting.java        # compiles in memory and runs; no .class written

Rules worth knowing:

  • The file may contain multiple classes; the first top-level class is the entry point and must have a valid main.
  • The file name does not have to match the public class name in this launch mode (the normal file-name rule applies only when you compile to .class with javac).
  • Arguments after the file name are passed to main: java Greeting.java a b c.

SDET note

Single-file launch (and jshell) make great scratchpads for reproducing a flaky behavior or confirming an API's edge case in isolation — exactly the kind of quick experiment that beats guessing what an AI-generated snippet "probably" does.

Comments

java
// single-line
/* multi-line
   comment */
/** Javadoc — documents the next declaration; tooling extracts it. */

Comments are stripped by the compiler. A subtle trap: /* ... */ does not nest, so /* outer /* inner */ still outer */ ends at the first */ and the trailing text is a syntax error.

Key Takeaways

  • javac compiles .java → bytecode .class; the JVM runs bytecode. JDKJREJVM.
  • Source order is package → imports → types. At most one public top-level type, and its name must match the file name (when compiling to .class).
  • A launchable main is public static void main(String[] args)String[]/String... both ok, name of the param is irrelevant, static is mandatory. Wrong signatures compile but fail at launch.
  • java.lang and same-package types need no import; * is non-recursive; explicit imports beat on-demand and resolve ambiguity; an import is never strictly required.
  • Run with the class name / FQCN, not the file: java com.example.Greeting. Since Java 11, java Greeting.java runs source directly.

Lesson Quiz

Lesson Quiz · How a Java Program Is Structured & Run0 / 10
  1. Which tool turns a .java source file into a .class file?

    • Ajava
    • Bjavac
    • Cjar
    • DThe JVM at startup
  2. Which of these are valid, launchable main method signatures? (select all that apply) (select all that apply)

    • Apublic static void main(String[] args)
    • Bstatic public void main(String... xyz)
    • Cpublic void main(String[] args)
    • Dpublic static int main(String[] args)
  3. A file named Main.java contains: public class Greeting { public static void main(String[] a){} }. What happens?

    • ACompiles and runs fine
    • BCompile error: public type name must match the file name
    • CCompiles, but fails at launch
    • DRuntime ClassNotFoundException
  4. Given two on-demand imports `import java.util.*;` and `import java.sql.*;`, referring to the simple name `Date` will:

    • AUse java.util.Date by default
    • BUse java.sql.Date by default
    • CFail to compile due to ambiguity
    • DPick whichever import is listed first
  5. Which statements about imports are TRUE? (select all that apply) (select all that apply)

    • ATypes in java.lang are imported automatically
    • Bimport java.util.*; also imports java.util.concurrent types
    • CAn import is never strictly required; you can use fully qualified names
    • DA single-type import takes precedence over an on-demand (*) import
  6. For `java Greeting one two three`, what is args.length inside main?

    • A4 (program name is args[0])
    • B3
    • C0
    • DIt throws ArrayIndexOutOfBounds
  7. Which command correctly runs the compiled class com.example.Greeting?

    • Ajava com/example/Greeting.class
    • Bjava com.example.Greeting
    • Cjavac com.example.Greeting
    • Djava Greeting.class
  8. Since which Java version can you run a single source file directly with `java Greeting.java` (no separate javac)?

    • AJava 8
    • BJava 11
    • CJava 17
    • DJava 21
  9. Put the elements of a source file in the only legal order.

    • Aimports, package, type declarations
    • Bpackage, imports, type declarations
    • Ctype declarations, package, imports
    • Dpackage, type declarations, imports
  10. What is the result of this fragment inside a method? /* outer /* inner */ x = 1;

    • ABoth comments nest; x = 1 executes
    • BCompile error: block comments do not nest, so `still outer */` (here `x = 1;`) is left dangling/parsed oddly
    • CRuns fine; everything after /* is ignored
    • Dx is set to the value inner

Next: Types, Variables & var. Run the matching code in labs/.../m00_foundations and try java on a single file yourself.