Java File

Su Suriya Ravichandran Updated 14 Nov 2026
7 min read ·Lesson 36 of 133

Java source code lives in plain text files with the .java extension. The compiler places specific requirements on these files: how they are named, what they may contain, in what order, and where they sit in the folder structure. Those rules exist so that both the compiler and the JVM can find any class by its name alone.

Anatomy of a Source File

A .java file contains, in this order:

// 1. Optional package declaration (at most one, must come first)
package com.example.billing;

// 2. Optional import declarations
import java.time.LocalDate;
import java.util.List;

// 3. One or more type declarations: class, interface, enum, record
public class Invoice {
    private final List<String> items;
    private final LocalDate issued;

    public Invoice(List<String> items) {
        this.items = items;
        this.issued = LocalDate.now();
    }
}

Comments and blank lines may appear anywhere. Any other order (an import before the package, or after a class) is a compile error.

The Naming Rule

A file may contain at most one public top-level type, and the file must be named after it exactly, including capitalization, followed by .java.

Public classRequired file name
public class InvoiceInvoice.java
public record Point(...)Point.java
public interface PaymentGatewayPaymentGateway.java
public enum OrderStatusOrderStatus.java
// saved as invoice.java
public class Invoice { }
invoice.java:1: error: class Invoice is public, should be declared in a file named Invoice.java

The rule lets the compiler locate the source for any public class by name. When Billing.java refers to Invoice, javac knows to look for Invoice.java (or Invoice.class) in the right directory without reading every file in the project.

Case matters even on Windows and macOS, whose file systems usually ignore case. Treating Invoice.java and invoice.java as interchangeable leads to errors when the code is built on Linux, where they are different files.

Multiple Types in One File

A file can contain additional non-public top-level types:

// Shapes.java
public class Shapes {
    public static void main(String[] args) {
        System.out.println(new Circle(2).area());
    }
}

class Circle {                       // package-private: no public modifier
    private final double r;
    Circle(double r) { this.r = r; }
    double area() { return Math.PI * r * r; }
}

Compiling produces two class files, Shapes.class and Circle.class. Circle is visible only to classes in the same package.

This is legal, but the common convention is one top-level type per file. A reader looking for Circle would not think to open Shapes.java, and tools that navigate by file name cannot find it. Small helper types that belong to one class are better written as nested types inside that class.

A file with no public type may have any name, but naming it after its main type keeps the project navigable.

Packages and Directory Structure

The package declaration places the class in a namespace. The class's fully qualified name combines both: com.example.billing.Invoice.

The source file should sit in a directory path matching the package:

src/
└── com/
    └── example/
        └── billing/
            ├── Invoice.java       // package com.example.billing;
            └── LineItem.java      // package com.example.billing;

When compiled with -d, the class files are placed in the same structure automatically:

javac -d out src/com/example/billing/*.java
out/
└── com/example/billing/
    ├── Invoice.class
    └── LineItem.class

For class files, the directory structure is mandatory at runtime: the JVM finds com.example.billing.Invoice by looking for com/example/billing/Invoice.class under each classpath entry. For source files, javac is lenient if you list files explicitly, but build tools, IDEs, and --source-path all assume the matching layout. Always keep it.

Package names are lowercase and typically start with a reversed domain name you control (com.gocourse.lms, org.apache.commons), which avoids collisions between libraries from different organizations.

Files Without a Package

A file without a package statement belongs to the unnamed package:

// Hello.java, no package line
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello");
    }
}

This is convenient for single-file experiments and is used in the early lessons of this tutorial. Real projects always use packages, because classes in the unnamed package cannot be imported by classes that are in a named package.

Imports

Import declarations let you refer to types from other packages by their simple name:

import java.util.List;              // single-type import
import java.util.*;                 // on-demand import: every type in java.util
import static java.lang.Math.PI;    // static import: a static member
import static java.lang.Math.*;     // all static members of Math
FormUse
Single-type importThe default; makes dependencies explicit
On-demand (*)Shorter, but can introduce name clashes and hides what is used
Static importConstants or utility methods used very frequently, such as assertEquals in tests

Imports affect only how names are written in the source. They do not load or include code, and unused imports have no runtime cost; the compiler simply ignores them (IDEs flag them for tidiness).

Types in java.lang (String, Math, Integer, System, Thread) and types in the same package are available without any import.

When two imported packages contain a type with the same name, the simple name is ambiguous:

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

Date d;    // compile error: reference to Date is ambiguous

Import the one you mean explicitly (import java.util.Date;) or write the fully qualified name.

Text Encoding

Source files are text, and their character encoding matters whenever they contain non-ASCII characters (accented letters, ₹, emoji, non-Latin scripts) in strings or comments:

String price = "₹1,499";
String greeting = "வணக்கம்";

Since JDK 18, javac reads source files as UTF-8 by default on every platform. With older JDKs, the default depended on the operating system, and a file saved as UTF-8 could be misread on Windows, producing garbled text or unmappable character errors. Save source files as UTF-8, and when building with older JDKs specify it explicitly:

javac -encoding UTF-8 Greeting.java

Compact Source Files (Java 25)

Java 25 finalized compact source files and instance main methods, aimed at beginners and small scripts. A file may omit the class declaration entirely:

// Hello.java
void main() {
    IO.println("Hello, compact Java!");
}
java Hello.java

The compiler wraps the contents in an implicitly declared class. main can be an instance method with no parameters, and java.lang.IO provides simple console methods such as IO.println and IO.readln. Compact source files automatically have access to all public types in the java.base module without imports.

This form is useful for learning and quick scripts. It is not available on earlier versions, and ordinary projects with multiple classes continue to use explicit class declarations. This tutorial uses the standard form so that examples compile on any recent LTS.

Other Files in a Java Project

FilePurpose
.javaSource code
.classCompiled bytecode, generated by javac; never edited by hand
.jarZIP archive of class files and resources, with a manifest
module-info.javaDeclares a module: its name, dependencies, and exported packages
package-info.javaJavadoc and annotations for a whole package
MANIFEST.MFMetadata inside a JAR, including the Main-Class entry point
pom.xml / build.gradleBuild configuration for Maven or Gradle
.propertiesKey-value configuration, commonly read with java.util.Properties

A typical Maven or Gradle project separates them by convention:

my-app/
├── pom.xml                       (or build.gradle)
└── src/
    ├── main/
    │   ├── java/                 application source, in package directories
    │   └── resources/            config files, templates, static assets
    └── test/
        └── java/                 test source

Following this layout means build tools, IDEs, and other developers know where everything is without configuration.

Practical Example: A Two-File Program

src/
└── com/example/temps/
    ├── App.java
    └── Converter.java
// src/com/example/temps/Converter.java
package com.example.temps;

public class Converter {
    public static double toFahrenheit(double celsius) {
        return celsius * 9 / 5 + 32;
    }
}
// src/com/example/temps/App.java
package com.example.temps;

public class App {
    public static void main(String[] args) {
        double[] readings = {0, 21.5, 37, 100};
        for (double c : readings) {
            System.out.printf("%6.1f °C = %6.1f °F%n", c, Converter.toFahrenheit(c));
        }
    }
}
javac -d out src/com/example/temps/*.java
java -cp out com.example.temps.App

Output:

   0.0 °C =   32.0 °F
  21.5 °C =   70.7 °F
  37.0 °C =   98.6 °F
 100.0 °C =  212.0 °F

Each public class is in its own file named after it. Both files declare the same package, so App uses Converter without an import. The directories match the package name, -d out mirrors that structure for the class files, and the program is run by its fully qualified name, com.example.temps.App.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about Java File and get answers drawn from it.

Signed-in readers only.