Appearance
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, andjava. - Describe the anatomy of a source file and the "one public top-level type per file" rule.
- Write a valid
mainmethod 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:
| Term | What it is | Contains |
|---|---|---|
| JVM | The runtime engine that executes bytecode. | — |
| JRE | Java Runtime Environment: everything needed to run Java. | JVM + core libraries |
| JDK | Java 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 (Greeting→Greeting.java).
java
// File: Greeting.java ✅ public type matches file name
public class Greeting {}
class Helper {} // non-public companion types are fine in the same fileExam 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
publicandstatic, returnvoid, and be namedmain. - Must take a single
String[]parameter. The parameter name is irrelevant (args,xyz, whatever). String[] args,String args[], and varargsString... argsare all accepted.- The order of
public staticdoesn't matter (static publicis fine).finalis 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-demandKey rules the exam tests:
java.langis imported automatically —String,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 injava.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.Listandjava.awt.List), usingListis 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 .classA 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 writtenRules 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
.classwithjavac). - 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
javaccompiles.java→ bytecode.class; the JVM runs bytecode. JDK ⊃ JRE ⊃ JVM.- 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
mainispublic static void main(String[] args)—String[]/String...both ok, name of the param is irrelevant,staticis mandatory. Wrong signatures compile but fail at launch. java.langand 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.javaruns source directly.
Lesson Quiz
Which tool turns a .java source file into a .class file?
Which of these are valid, launchable main method signatures? (select all that apply) (select all that apply)
A file named Main.java contains: public class Greeting { public static void main(String[] a){} }. What happens?
Given two on-demand imports `import java.util.*;` and `import java.sql.*;`, referring to the simple name `Date` will:
Which statements about imports are TRUE? (select all that apply) (select all that apply)
For `java Greeting one two three`, what is args.length inside main?
Which command correctly runs the compiled class com.example.Greeting?
Since which Java version can you run a single source file directly with `java Greeting.java` (no separate javac)?
Put the elements of a source file in the only legal order.
What is the result of this fragment inside a method? /* outer /* inner */ x = 1;
Next: Types, Variables & var. Run the matching code in labs/.../m00_foundations and try java on a single file yourself.