1.3 Structure of a Java Program & The main Method

Key Takeaways

  • A Java source file (.java) enforces an unbending order — an optional package declaration first, then import statements, then class or interface declarations — and may declare at most one public class, whose name must match the base file name with exact case sensitivity.
  • The standalone application entry point must strictly declare the signature public static void main(String[] args); altering modifiers, return types, or parameter types prevents JVM launching.
  • The java.lang package is automatically imported into every Java compilation unit by the compiler, eliminating the need to import fundamental types such as System, String, and Math.
  • Java supports single-line (//), multi-line (/* */), and Javadoc (/** */) comments; multi-line comments cannot be nested within one another without causing compilation errors.
  • Java SE 8 defines 50 lowercase reserved keywords plus the reserved literals true, false, and null; const and goto are reserved but carry no semantics, while String, System, and main are ordinary identifiers rather than reserved words.
Last updated: September 2026

1.3 Structure of a Java Program & The main Method

[!NOTE] Exam Focus: In the 1Z0-811 examination, questions frequently test your ability to spot syntactically invalid Java source file layouts. You must know the mandatory ordering of file elements (package -> imports -> class), understand why a file name must match its public class, recognize valid versus invalid main method signatures, and identify comment syntax errors.

A Java source code file (bearing the .java extension) is a structured compilation unit that adheres to strict grammatical and syntactical rules defined by the Java Language Specification. Violating these rules results in immediate compile-time errors.


Anatomical Layout of a Java Source File (.java)

A Java source file can contain three primary top-level elements, which must appear in an exact sequential order:

Package DeclarationImport StatementsClass / Interface Declarations\text{Package Declaration} \longrightarrow \text{Import Statements} \longrightarrow \text{Class / Interface Declarations}

File ElementKeywordQuantity in FileOrder RulePurpose
Package DeclarationpackageZero or One (0..1)Must be the first non-comment statementDefines the logical namespace and folder directory structure
Import StatementsimportZero or Many (0..*)Must appear after package, before class declarationsMakes external types accessible without fully qualified names
Type Declarationsclass, interface, enumOne or Many (1..*)Must appear after import statementsDeclares classes, interfaces, or enumerations
// Line 1: Comments and whitespace may appear anywhere in the file
package com.oracle.certification; // 1. Package declaration (at most one)

import java.util.ArrayList;        // 2. Import statements (zero or more)
import java.time.LocalDate;

public class ExamCandidate {       // 3. Class declaration (at most one public class)
    // Fields, constructors, and methods
}

[!WARNING] Ordering Violations Cause Compiler Errors: If an import statement precedes a package declaration, or if a package declaration appears after a class declaration, the Java compiler will reject the file with a compilation error. The only tokens permitted prior to the package declaration are comments (//, /* */, /** */) and whitespace.


Package Declarations: Namespaces and File Paths

A package provides a mechanism for grouping related classes, interfaces, and enumerations into a unified namespace. Packages serve two fundamental purposes:

  1. Preventing naming collisions: Two distinct classes can share the identical simple name Date as long as they reside in different packages (java.util.Date versus java.sql.Date).
  2. Access protection: Packages establish an access control boundary. Package-private members (members declared without an explicit access modifier) are accessible only to other classes residing in the identical package.

Syntax and Directory Mapping

The package declaration consists of the package keyword followed by a dot-separated hierarchical identifier terminated by a semicolon:

package com.company.finance.payroll;

By industry convention, package names are written entirely in lowercase letters to avoid confusion with class names, using the reversed domain name of an organization (com.company.project). On the physical file system, package hierarchies must map directly to subdirectories. The class com.company.finance.payroll.SalaryCalculator must reside inside the directory path:

com/company/finance/payroll/SalaryCalculator.java

If a source file omits the package statement altogether, the types defined within that file belong to the default package (unnamed package). While legal in simple learning exercises, the default package should never be used in production applications because classes in named packages cannot import classes from the default package.


Import Statements: Explicit vs. Wildcard Imports

To use a class located in another package, Java developers have two choices:

  1. Use the Fully Qualified Class Name (FQCN) throughout the code:
    java.util.ArrayList<String> list = new java.util.ArrayList<String>();
    
  2. Use an import statement at the top of the file, allowing the class to be referenced by its simple name:
    import java.util.ArrayList;
    // ...
    ArrayList<String> list = new ArrayList<String>();
    

Single-Type vs. On-Demand Wildcard Imports

Java supports two syntactical styles of import statements:

  • Single-Type Import: Explicitly names the single class or interface being imported:
    import java.util.Scanner;
    import java.util.List;
    
  • Type-Import-on-Demand (Wildcard *): Uses an asterisk (*) to import all public classes and interfaces declared directly within the specified package:
    import java.util.*;
    

[!IMPORTANT] Wildcards Do NOT Import Sub-packages: A wildcard import does not recursively import classes from sub-packages. For example, import java.awt.*; imports classes directly inside java.awt (such as java.awt.Color and java.awt.Font), but does not import classes inside java.awt.event.* (such as java.awt.event.ActionEvent). A separate import statement (import java.awt.event.*;) is required.

[!TIP] Performance Myth: Using a wildcard import (import java.util.*;) does not degrade runtime application performance or bloat the compiled .class bytecode. The Java compiler resolves imports at compile time; the generated bytecode contains only direct references to the specific types actually utilized.

The Automatic java.lang Import

Every Java compilation unit implicitly and automatically imports the entire java.lang package:

import java.lang.*; // Automatically included by the compiler behind the scenes

Consequently, developers never need to write import statements for ubiquitous core types like System, String, Math, Object, Thread, Exception, or primitive wrapper classes like Integer, Double, and Boolean.

Ambiguity and Name Collisions

When a source file imports two packages that contain a class with the identical name, a naming collision can occur:

import java.util.*;
import java.sql.*;

public class Report {
    Date reportDate; // COMPILE ERROR: Reference to 'Date' is ambiguous!
}

Because both java.util.Date and java.sql.Date exist, the compiler cannot determine which class is intended. To resolve this ambiguity, the developer must either:

  1. Add an explicit single-type import, which always takes precedence over wildcard imports:
    import java.util.Date; // Takes precedence over java.sql.*
    
  2. Use the fully qualified class name directly at the variable declaration site:
    java.util.Date reportDate = new java.util.Date();
    

Class Declarations and File Naming Rules

A Java source file can define one or more classes, interfaces, or enums. However, two strict rules govern top-level declarations:

The Single Public Class Rule

  • A single .java file can contain at most one public top-level class.
  • If a file contains a public class, the base name of the .java file must match the name of that public class exactly, including letter case.
// File MUST be saved exactly as: Vehicle.java
public class Vehicle { // Matches filename
    // ...
}

class Engine { // Valid: package-private class in the same file
    // ...
}

If the file above were saved as vehicle.java (lowercase v) on a case-sensitive file system, or as Transport.java, the compiler would fail with the error: class Vehicle is public, should be declared in a file named Vehicle.java.

Files with Zero Public Classes

A .java file is not required to declare any public class. If a file contains only package-private (default access) classes, the file name can be any legal identifier ending with .java, even if it does not match any of the class names declared within it:

// File saved as: Helpers.java (Fully valid!)
class MathHelper {
    // ...
}

class StringHelper {
    // ...
}

Deconstructing the main Method Signature

To execute a Java program as an independent standalone console application, the JVM requires an entry point. The Java launcher strictly expects the following method signature:

public static void main(String[] args)

Every single keyword in this signature serves a vital architectural purpose:

public        static        void        main        (String[] args)
  │             │            │            │                │
  │             │            │            │                └─ Array of command-line String arguments
  │             │            │            └─ Exact identifier required by the JVM launcher
  │             │            └─ Method returns no value to caller
  │             └─ Callable directly on the class without instantiating an object
  └─ Accessible by the JVM launcher from any package
  1. public: An access modifier. The entry point must be universally accessible so the JVM launcher, which executes outside the application's package, can locate and invoke it.
  2. static: A method modifier indicating that the method belongs to the class itself rather than any specific instance. When launching an application, the JVM does not instantiate an object of the host class (e.g., new Main()). Declaring the method static allows the JVM to invoke Main.main() directly.
  3. void: The return type. The method performs operations and returns no value back to the JVM. (To exit with a specific status code, an application calls System.exit(int status)).
  4. main: The exact method identifier (all lowercase) required by the JVM specification. Methods named Main, MAIN, or start will not be recognized as entry points.
  5. String[] args: The parameter list. The JVM gathers all command-line arguments passed to the program and bundles them into an array of String objects.

Permissible Syntax Variations

The 1Z0-811 exam frequently tests candidate recognition of valid alternative syntaxes for main:

  • Bracket placement on array: Both String[] args and String args[] (or String []args) are valid.
  • Parameter identifier name: The parameter does not have to be named args. Any legal Java identifier is valid (e.g., String[] parameters or String[] data).
  • Varargs syntax (Java 5+): Variable-length argument lists (String... args) are interchangeable with String[] args and are accepted by the JVM launcher.
  • Order of modifiers: The access modifier and static keyword can be placed in reverse order: static public void main(String[] args) is completely valid, although public static is universal convention.

Invalid main Signatures That Compile but Cannot Be Launched

The following signatures compile without error as regular methods, but the JVM launcher will fail to recognize them as valid application entry points at runtime:

Invalid SignatureReason It Fails as an Entry Point
public void main(String[] args)Missing static modifier; JVM cannot invoke without an instance
static void main(String[] args)Missing public modifier (package-private); JVM launcher cannot access
public static int main(String[] args)Return type is int instead of void
public static void Main(String[] args)Capitalized M; Java is strictly case-sensitive
public static void main(String args)Parameter is a single String, not an array (String[])

Statements, Blocks, and Variable Scoping

Statements

A statement is a complete unit of execution in Java, analogous to a complete sentence in natural language. In Java, simple statements must terminate with a semicolon (;):

int count = 5;          // Declaration and assignment statement
count++;                // Increment statement
System.out.println();   // Method invocation statement
;

An isolated semicolon by itself is an empty statement, which is syntactically legal but performs no operation.

Blocks and Variable Scope

A block (also called a compound statement) consists of zero or more statements enclosed within a matching pair of curly braces: { and }.

  • Blocks can be used wherever a single statement is permitted (such as after if, while, or for loops).
  • Blocks establish a lexical variable scope. Variables declared inside a block are visible only within that block and its nested inner blocks. Once execution exits the enclosing closing brace }, the local variables declared within that block cease to exist:
public void calculate() {
    int x = 10; // In scope throughout calculate()
    {
        int y = 20; // In scope only within this inner block
        System.out.println(x + y); // 30
    }
    // System.out.println(y); // COMPILE ERROR: 'y' cannot be resolved to a variable!
}

Java Reserved Words

Oracle's Basic Java Elements topic area lists the objective "use Java reserved words" explicitly, and the exam tests it by showing you an identifier that collides with a keyword. A reserved word is a token the Java grammar claims for itself; it can never be used as the name of a variable, method, class, package, or label.

Java SE 8 defines 50 reserved keywords, plus 3 reserved literals (true, false, null) that are technically literal values rather than keywords but are equally off-limits as identifiers:

CategoryReserved Words
Primitive typesboolean, byte, char, short, int, long, float, double
Control flowif, else, switch, case, default, for, while, do, break, continue, return
Exception handlingtry, catch, finally, throw, throws, assert
Class and object modelclass, interface, enum, extends, implements, new, this, super, instanceof, void
Access modifierspublic, protected, private
Other modifiersstatic, final, abstract, native, synchronized, transient, volatile, strictfp
Packagingpackage, import
Reserved but unusedconst, goto
Reserved literalstrue, false, null

Four Rules the Exam Actually Tests

  1. Keywords are always lowercase. Every reserved word is written entirely in lowercase. Because Java is case-sensitive, Int, Class, and New are not reserved — they are perfectly legal identifiers (though appallingly poor style).
  2. const and goto are reserved but do nothing. Java claims both tokens so that C and C++ programmers get a clear compiler error instead of silently wrong behaviour, but the language defines no semantics for either. Declaring int goto = 5; fails to compile.
  3. var is not a keyword — and does not exist in Java 8. Local variable type inference arrived in Java 10, and even there var is a reserved type name, not a keyword. On the 1Z0-811 exam (Java SE 8), var x = 10; simply fails to compile because no type named var exists.
  4. Common class names are not reserved. String, System, Math, Integer, Object, and main are ordinary identifiers supplied by the standard library, not reserved words. Writing int String = 5; compiles — it merely shadows the type name inside that scope and creates a maintenance nightmare.
// COMPILE ERRORS: reserved words cannot be identifiers
// int class = 10;        // 'class' is reserved
// double new = 3.14;     // 'new' is reserved
// String final = "text"; // 'final' is reserved
// boolean null = true;   // 'null' is a reserved literal

// LEGAL (but terrible style): these are NOT reserved words
int Class = 10;    // Capital C -> ordinary identifier
int Integer = 42;  // Shadows the wrapper class name inside this scope
int main = 7;      // 'main' is just a method name convention

Identifier Rules That Travel With Reserved Words

Beyond avoiding reserved words, a legal Java identifier must:

  • Begin with a letter, a currency symbol ($), or an underscore (_) — never a digit. int 2ndPlace; fails to compile.
  • Contain only letters, digits, $, and _ after the first character. Hyphens, spaces, and operators such as - or + are illegal.
  • Be a single unreserved token. A lone underscore (_) is legal in Java 8 but produces a compiler warning, and it became a hard error in Java 9.

Comments in Java Source Code

Comments allow developers to document code logic and intent. The Java compiler ignores comments during tokenization; comments generate zero bytecode and have zero impact on program execution. Java supports three styles of comments:

1. Single-Line Comments

Initiated by two forward slashes (//). Everything from // to the end of that physical line is ignored:

// This is a single-line comment
int total = 100; // Inline comment explaining variable total

2. Multi-Line (Traditional) Comments

Initiated by /* and terminated by */. Can span multiple lines:

/*
 * Multi-line comment
 * spanning across multiple lines
 */
int bonus = 50;

[!WARNING] Nesting Prohibition: Multi-line comments cannot be nested! The first occurrence of */ encountered by the compiler immediately terminates the entire comment, leaving the remaining text as invalid code that triggers compiler errors:

/* Outer comment
   /* Inner nested comment */  <-- Terminates here!
   This text causes a COMPILE ERROR! */

3. Javadoc Documentation Comments

Initiated by a slash followed by two asterisks (/**) and terminated by */. These comments are inspected and processed by the JDK's javadoc tool to generate standardized HTML documentation:

/**
 * Calculates the annual interest accrued on a savings account.
 * 
 * @param principal The starting investment balance in USD
 * @param rate The annual interest rate as a decimal (e.g., 0.05)
 * @return The total interest earned over one year
 */
public double calculateInterest(double principal, double rate) {
    return principal * rate;
}

Standard Javadoc tags include @param (describes a method parameter), @return (describes the return value), @throws / @exception (documents exceptions thrown), @author (documents the developer), and @version (specifies version information).

Loading diagram...
Java Source File Organization and Entry Point Architecture
Test Your Knowledge

A developer writes a Java source code file containing a public class declaration. Which rule is strictly enforced by the Java compiler regarding the file structure and naming?

A
B
C
D
Test Your Knowledge

Consider the following class definition: public class Starter { public static void Main(String[] args) { System.out.println("Running..."); } } What happens when a developer compiles this file with javac Starter.java and attempts to run it with java Starter?

A
B
C
D
Test Your Knowledge

Why does a developer never need to include the statement import java.lang.*; to use ubiquitous classes like String, System, Math, or Integer in a Java source file?

A
B
C
D
Test Your Knowledge

Which one of the following variable declarations fails to compile in Java SE 8 because the identifier collides with a Java reserved word?

A
B
C
D