Java Program Structure
A Java source file follows a fixed structural order — package, imports, then a class holding fields, methods, and statements — that the compiler enforces.
Every Java source file follows a predictable structure: an optional package declaration, followed by import statements, followed by one or more type declarations (classes, interfaces, enums, records). Inside a class, fields hold state and methods hold behavior, built from statements and expressions grouped into blocks. This topic walks through that structure top to bottom, the way the compiler reads it.
Source-File Structure and Ordering
A .java file must follow this order when each part is present: package declaration, import declarations, then type declarations (classes/interfaces/enums/records). Nothing else (besides comments) may appear before the package declaration, and imports must come before any type declaration.
package com.example.app; // 1. package declaration (optional, at most one)
import java.util.List; // 2. imports (zero or more)
import java.util.ArrayList;
public class Application { // 3. type declaration(s)
// fields, methods
}Package Declaration
The package statement declares which namespace a class belongs to, helping avoid naming collisions and organizing related classes. It must be the first non-comment line in the file, if present. A file with no package declaration puts its class in the unnamed (default) package — fine for tiny examples, but avoided in real projects.
package com.example.util;Import Declarations
Imports let you refer to a class by its simple name instead of its fully qualified name. A single-type import names one class; a wildcard import (with *) brings in all public top-level types from a package (but not from subpackages).
java.lang (String, Object, Math, System, and friends) is imported automatically into every file — it never needs an explicit import statement.
import java.util.List; // single-type import
import java.util.*; // wildcard import (all top-level types in java.util)
import static java.lang.Math.PI; // static import (imports a static member)Class Declaration
A class declaration introduces a new type: an optional access modifier, the class keyword, the class name, and a body in braces. A source file may contain multiple top-level classes, but at most one may be public.
public class Application {
// class body: fields, methods, constructors, nested types
}Public Top-Level Class / File-Name Relationship
If a top-level class is declared public, the source file's name must exactly match that class name, including case, with a .java extension. This is a compiler-enforced rule, not a convention.
A file may still contain additional non-public top-level classes alongside the one public class, each compiling to its own .class file.
// File: Application.java
public class Application { } // OK: file name matches public class name
// File: App.java
public class Application { } // compile error: class Application is public,
// should be declared in a file named Application.javaFields
Fields are variables declared directly inside a class body (outside any method) that hold an object's or class's state. Instance fields belong to each object; static fields belong to the class itself and are shared across all instances (covered fully in the Variables topic).
public class Account {
private double balance; // instance field
private static int accountCount; // static (class) field
}Methods
Methods define behavior: an access modifier, optional modifiers (static, final...), a return type (or void), a name, a parameter list, and a body in braces. A method is invoked by name with matching arguments.
public class Calculator {
public int add(int a, int b) { // method: name "add", returns int
return a + b; // statement
}
}The main Method
main is the conventional entry point the JVM launcher looks for. It must be exactly public static void main(String[] args) — public so the JVM (outside the class) can call it, static so it can be invoked without creating an instance first, void because it returns nothing to the OS via a normal return value, and it accepts an array of command-line arguments as strings.
The parameter can also be written as String args[] (C-style array syntax) — both are legal and equivalent, though String[] args is the conventional modern style.
public static void main(String[] args) {
// program execution starts here
}Statements, Expressions, and Blocks
A statement is a complete unit of execution, usually terminated by a semicolon (e.g. a declaration, an assignment, a method call, a control-flow construct). An expression is anything that evaluates to a value (e.g. 2 + 3, a.compute(), x > 0). A block is a sequence of statements enclosed in braces { }, treated as a single unit — the body of a method, loop, or if branch is a block.
int total = 2 + 3; // expression (2 + 3) inside a declaration statement
if (total > 4) { // block starts
System.out.println("big");
} // block endsBraces and Semicolons
Braces { } delimit blocks: class bodies, method bodies, and control-flow bodies. Semicolons terminate individual statements, not blocks — a closing brace never needs a trailing semicolon (except after a class body used as part of certain expressions, which is unusual and rare in practice).
public class Empty {
} // no semicolon after a class body
int x = 5; // semicolon required after a statementComments
Java supports single-line (//), multi-line (/* */), and documentation (/** */) comments. See the dedicated Comments topic for full details and Javadoc conventions.
// single-line comment
/* multi-line
comment */
/** Javadoc comment describing the following element */Naming Conventions
Java's community-standard naming conventions (not compiler-enforced, but expected everywhere): classes and interfaces use UpperCamelCase (Account, Runnable); methods and variables use lowerCamelCase (getBalance, accountCount); constants (static final fields) use SCREAMING_SNAKE_CASE (MAX_SIZE); packages use all-lowercase, dot-separated, typically reverse-domain (com.example.app).
Command-Line Arguments
Arguments passed after the class name on the java command line are collected into the args array passed to main, as Strings — the program is responsible for parsing them into other types if needed.
$ java Application build release
// args[0] = "build", args[1] = "release"public static void main(String[] args) {
if (args.length > 0) {
System.out.println("First argument: " + args[0]);
}
}Basic Execution Flow
When you run java Application, the JVM loads the Application class, locates its main method, and begins executing statements in main sequentially — top to bottom, subject to control-flow constructs (if, loops, method calls) that redirect execution. The program ends when main returns, all non-daemon threads finish, or System.exit is called.
Key Takeaways
Source-file order is fixed: package declaration, then imports, then type declarations.
A public top-level class's name must exactly match its file's name.
Fields hold state, methods hold behavior; both live inside a class body.
main must be public static void main(String[] args) to be recognized as the entry point.
Statements end in semicolons; blocks are grouped in braces and contain zero or more statements.
// File: Main.java public class App { public static void main(String[] a) {} }
// File: App.java public class App { public static void main(String[] a) {} }
A public top-level class name must exactly match its source file name, or the compiler rejects it.
public static void Main(String[] args) { } public static void main(String[] args) { }
Java is case-sensitive; the entry point must be lowercase main, not Main (a common mistake for programmers coming from C#).
What is the required order of package declaration, imports, and type declarations in a .java file?
Package declaration first (if present), then import declarations, then type (class/interface/enum/record) declarations.
Why must a public top-level class's file name match the class name exactly?
It is a rule enforced by the Java compiler so the class-loading mechanism can locate the .class file predictably by name; violating it is a compile-time error.
What are the four required parts of the main method's signature for it to be recognized as the entry point?
public, static, void, and the parameter String[] args (parameter name can vary, but the type must be an array of String).
Distinguish a statement from an expression with an example.
An expression evaluates to a value, e.g. 2 + 3. A statement is a complete executable unit, often built from an expression plus a semicolon, e.g. int x = 2 + 3;
Can a single .java file contain more than one top-level class? What is the restriction?
Yes, but at most one of those top-level classes may be declared public, and if one is public, the file name must match that public class's name.
How are command-line arguments made available to a Java program, and as what type?
They are collected into the String[] args array passed to main, always as strings — the program must parse them into other types itself if needed.
Why does java.lang not need an explicit import statement?
The java.lang package (containing String, Object, Math, System, etc.) is implicitly imported into every Java source file automatically.
Write a Java program named Greeter.java whose main method prints the first command-line argument, or 'no name given' if none was supplied.
public class Greeter { public static void main(String[] args) { if (args.length > 0) { System.out.println("Hello, " + args[0]); } else { System.out.println("no name given"); } } }
Checking args.length before indexing avoids an ArrayIndexOutOfBoundsException when no arguments are passed.
Assuming this is saved as Tool.java, does this compile?
Yes — two non-public top-level classes can share one file freely. This only becomes a problem if one of them is declared public and its name doesn't match the file name.
Write a short program that declares one instance field, one static field, and one method that uses both.
public class Counter { private int localValue; // instance field private static int totalCreated; // static field public Counter(int value) { this.localValue = value; totalCreated++; } public void report() { System.out.println("value=" + localValue + ", totalCreated=" + totalCreated); } } localValue is per-instance state; totalCreated is shared class-wide state incremented once per construction.
public class Tool {
}
public class Helper {
}