JAVA β€’ FUNCTIONS AND PROGRAM STRUCTURE

Organizing Classes & Files β€” Organize code into multiple classes and files

Learn how to split your Java programs into separate classes and files for cleaner, reusable, and maintainable code.

Historical Context & Motivation

In the earliest days of programming, developers wrote entire programs inside a single file. As programs grew from a few dozen lines to hundreds of thousands, this approach became unmanageable. Imagine trying to find one sentence in a novel where every chapter is jammed onto one page β€” that is what reading a large, single-file program feels like. The need to organize code into separate, logical pieces drove the evolution of modern programming languages, including Java.

1960s
Structured Programming
Languages like ALGOL introduced the idea of grouping instructions into procedures and functions. This was the first step toward breaking code into reusable pieces instead of long, tangled scripts.
1980s
Object-Oriented Programming
Languages like C++ and Smalltalk popularized organizing code around objects and classes, bundling data with the functions that operate on it. This mindset became the foundation for Java.
1995
Java Is Released
Sun Microsystems released Java with a strict rule: each public class must live in its own .java file. This enforced clean organization from the very beginning of a project.
2000s–Present
Modern IDEs & Build Tools
Tools like IntelliJ IDEA, Eclipse, and build systems like Maven made managing dozens or hundreds of Java files easy, reinforcing multi-file project structures as the industry standard.

The central question this lesson addresses is straightforward: how do you break a Java program into multiple classes and files, and why does it matter? By the end, you will be comfortable creating multi-file Java projects and understanding how the pieces connect.

Core Principles & Definitions

Before diving into code, let's nail down the key ideas that guide how Java programs are organized. Each principle below tackles one aspect of keeping your codebase clear and manageable.

1

One Public Class Per File

Java requires that every public class be placed in a file whose name exactly matches the class name, including capitalization. For example, Dog.java must contain public class Dog.
2

Separation of Concerns

Each class should handle one responsibility. A class representing a student should not also handle printing report cards. Keeping responsibilities separate makes code easier to read, test, and change.
3

Packages for Grouping

A package is like a folder that groups related classes together. You declare a package at the top of a file with package myapp.models; and match it to the directory structure on disk.
4

Import Statements

When one class needs to use another class from a different package, you add an import statement at the top of the file, such as import myapp.models.Student;. Classes in the same package can see each other without imports.
5

Access Modifiers

Keywords like public, private, and protected control which classes can access a class's fields and methods. Proper use of access modifiers keeps your code secure and organized.
✦ KEY TAKEAWAY
Think of organizing classes like organizing a school. Each class is a teacher with a specific subject to teach. Each file is that teacher's classroom. A package is a department (Math, Science, English). You wouldn't cram all teachers into one room, and you shouldn't cram all classes into one file.

Visual Explanation β€” Project Structure

The diagram below shows a typical multi-file Java project. Notice how files are organized into directories that match their package names, and how the Main class sits at the top level while model classes are grouped in a models sub-package.

A multi-file Java project with a root package myapp containing Main.java and a sub-package models containing Student.java and Course.java. The code snippets at the bottom show how each file declares its package and how Main imports the model classes.

In the diagram, each .java file contains exactly one public class. The directory structure on disk mirrors the package declarations inside each file. The Main.java file uses an import statement to pull in the classes from the models package, allowing it to create Student and Course objects.

How It Works β€” Compilation & Linking

When your Java project spans multiple files, you need to understand how the Java compiler (javac) processes everything. The compiler reads each .java file, checks that the class name matches the filename, resolves import statements to locate referenced classes, and then produces a corresponding .class file containing bytecode. The Java Virtual Machine (JVM) then runs the bytecode at runtime.

Step-by-Step Compilation Flow

  1. Write β€” Create separate .java files, one public class per file, with matching filenames.
  2. Compile β€” Run javac myapp/Main.java. The compiler automatically finds and compiles dependencies like Student.java and Course.java.
  3. Resolve β€” The compiler uses package declarations and import statements to locate all referenced classes. If a class cannot be found, you get a compile-time error.
  4. Run β€” Execute with java myapp.Main. The JVM loads each .class file as needed.
⚠️ Filename Rule
If your public class is named GradeBook, the file must be named GradeBook.java β€” not gradebook.java or Gradebook.java. Java is case-sensitive. Getting this wrong is one of the most common beginner mistakes.

An important detail is that you can have non-public (default access) classes in the same file as a public class. However, this is generally discouraged because it hides classes in unexpected places. The standard practice is one class per file, period.

Packages & Access Modifiers in Detail

As your project grows, you will want to group related classes into packages. A package is both a logical grouping in your source code and a physical folder on your hard drive. Understanding how packages interact with access modifiers is essential for controlling which classes can see and use each other.

This diagram shows how access modifiers determine visibility between classes in the same package and across different packages. Classes within myapp.models can access each other's public, protected, and default members. The Main class in a different package can only access public members.
Java Access Modifier Visibility Summary
ModifierSame ClassSame PackageSubclass (Other Pkg)Any Class
publicβœ…βœ…βœ…βœ…
protectedβœ…βœ…βœ…βŒ
default (no keyword)βœ…βœ…βŒβŒ
privateβœ…βŒβŒβŒ

Worked Example β€” Building a Multi-File Project

Let's walk through creating a small Java project from scratch. We will build a simple school roster application with three classes spread across two packages.

Creating a Multi-File School Roster App
1
Step 1 β€” Plan the ClassesWe need three classes: Student (holds a student's name and GPA), Classroom (holds a list of students and a room number), and Main (the entry point that creates objects and prints results). We will put Student and Classroom in the school.models package and Main in the school package.
3 classes, 2 packages, 3 files
2
Step 2 β€” Create Directory StructureCreate the folder hierarchy to match the packages. On your file system, make a school/ folder containing Main.java, and inside it a models/ folder containing Student.java and Classroom.java.
school/Main.java, school/models/Student.java, school/models/Classroom.java
3
Step 3 β€” Write Student.javaBegin with the package declaration: package school.models;. Then define the class with private fields (name and gpa), a constructor, and public getter methods. Making fields private and providing getters follows the principle of encapsulation β€” only the Student class controls how its data is accessed.
public class Student { private String name; private double gpa; ... }
4
Step 4 β€” Write Classroom.javaSame package declaration: package school.models;. This class holds an ArrayList<Student> and a method addStudent(Student s). Because Classroom and Student are in the same package, Classroom can reference Student without an import. We also add a method getAverageGPA() that loops through students and computes the mean.
public class Classroom { private ArrayList<Student> students; ... }
5
Step 5 β€” Write Main.java & CompileDeclare package school; and add import school.models.*; at the top. In the main method, create a Classroom, add a few Students, and print the average GPA. Compile from the parent directory with javac school/Main.java and run with java school.Main.
Output: Average GPA: 3.5

Strengths & Limitations of Multi-File Organization

Splitting code into multiple files and classes is overwhelmingly beneficial, but it is worth understanding the trade-offs, especially for small versus large projects.

Multi-File Organization: Strengths vs. Limitations
StrengthsLimitations
Readability β€” Each file is short and focused, making it easy to find what you need.Overhead for tiny programs β€” For a 20-line script, creating three files feels like overkill.
Reusability β€” A well-written Student class can be used in many different programs without changes.Navigation β€” With dozens of files, you need good tools (an IDE) to jump between them efficiently.
Team collaboration β€” Multiple developers can work on different files simultaneously without merge conflicts.Circular dependencies β€” If class A depends on class B and class B depends on A, you can create confusing tangles. Good design avoids this.
Testability β€” Individual classes can be tested independently using tools like JUnit.Learning curve β€” Beginners must understand packages, imports, and access modifiers before multi-file projects feel natural.
✦ KEY TAKEAWAY
Think of multi-file organization like a well-organized toolbox. When your project is small (a couple of screwdrivers), a single drawer is fine. But as your tool collection grows, you need labeled compartments. The small upfront cost of organizing pays off enormously when you (or a teammate) need to find the right tool six months later.

Connection to Advanced Concepts

The skills you are building now lay the groundwork for more sophisticated Java features and real-world software engineering practices. Below is a comparison of what you have learned versus what comes next as you advance.

Current Knowledge vs. Advanced Topics
What You Know NowWhat Comes Next
Organizing classes into packages with foldersJava Modules (JPMS) β€” Introduced in Java 9, modules group packages together and add another layer of encapsulation for large-scale applications.
Using import to reference classes from other packagesDependency management β€” Tools like Maven and Gradle automatically download and manage thousands of external libraries (JARs) that your project can import.
One class per file with clear responsibilitiesDesign patterns β€” Patterns like MVC (Model-View-Controller) formalize how to divide responsibilities across many classes in a predictable structure.
Compiling multiple files with javacBuild automation β€” Build tools compile, test, and package your entire project with a single command, handling hundreds of source files automatically.

The essential insight is that everything in professional Java development scales up from what you are learning here. A project with 3 files and 2 packages follows the exact same rules as a project with 3,000 files and 200 packages. Master the fundamentals now, and the advanced tools will feel like natural extensions rather than intimidating new concepts.

Practice Problems

PROBLEM 1 β€” CONCEPTUAL
Explain why Java requires that a public class named BankAccount must be saved in a file called BankAccount.java. What problem does this naming rule solve?
PROBLEM 2 β€” BASIC CALCULATION
You have a class Rectangle in package shapes.geometry and a class DrawingApp in package shapes. Write the exact directory structure (folders and file names) and the import statement that DrawingApp needs to use Rectangle.
PROBLEM 3 β€” INTERMEDIATE
You have two classes in the same package game.characters: Hero with a private int health field and a public int getHealth() method, and Enemy that wants to read the hero's health. Can Enemy directly access hero.health? Explain why or why not, and describe the correct approach.
PROBLEM 4 β€” APPLIED
You are building a music playlist app. Design a multi-file project with at least three classes. List each class's name, its package, its key fields and methods, and explain which access modifiers you would choose for each field. Describe how the main class connects to the others.
PROBLEM 5 β€” CRITICAL THINKING
A classmate argues: "Packages and imports are unnecessary complexity. I can just put all my classes in one folder with no package declarations and everything works." They are technically correct that this compiles. Write a response explaining at least three specific problems that will arise as their project grows beyond 10 classes, using concrete examples.

Lesson Summary

Organizing a Java project across multiple classes and files is a fundamental skill that scales from homework assignments to professional software. Each public class lives in its own .java file whose name matches the class name exactly. Related classes are grouped into packages, which correspond to folder directories on disk. When a class needs to use another class from a different package, it references it through an import statement.

Access modifiers (public, private, protected, and default) control which classes can see each other's members, enforcing encapsulation and separation of concerns. This structure makes code more readable, reusable, testable, and easier to maintain β€” whether you are working alone or on a team. The compilation process handles multi-file projects seamlessly: javac resolves imports automatically, and java loads each class file as needed at runtime.

Varsity Tutors β€’ Java β€’ Organizing Classes & Files