Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Packages and access modifiers

While a program fits in one file, keeping it tidy is easy. Real projects consist of hundreds of classes, and they are organised into packages. Packages together with access modifiers decide which code is visible to whom.

A package is a folder

A package is a named group of classes. The first line of a file, package shop.model;, says that the class belongs to the shop.model package, and the file must be located in the shop/model folder. In a project each public class lives in its own file with the same name:

// src/shop/model/Product.java
package shop.model;
 
public class Product {
    private final String title;
    private final double price;
 
    public Product(String title, double price) {
        this.title = title;
        this.price = price;
    }
 
    public String getTitle() {
        return title;
    }
 
    public double getPrice() {
        return PriceRules.round(price);
    }
}

Package names are written in lowercase, separated by dots. The full name of a class includes the package: shop.model.Product.

import

To use a class from another package, you import it — after that the short name is enough. The main file can stay compact, with void main():

// src/Main.java
import shop.model.Product;
 
void main() {
    Product tea = new Product("Tea", 4.499);
    IO.println(tea.getTitle() + ": " + tea.getPrice() + " €");
}

Classes from the java.lang package — String, Math, Integer — are always available. In a compact file like this one the other packages of the java.base module, such as java.util, are imported automatically too — that is why List and Map worked without import in the tutorial examples. In classic files with package you have to import them: import java.util.List;.

Four access levels

The modifier in front of a class, field or method determines where it can be accessed from:

ModifierAccessible to
publiceveryone
protectedits own package and subclasses in any package
no modifierits own package only
privateits own class only

Access without a modifier is called package-private. The usual rule: fields are private, methods for the outside world are public, and all helpers are package-private or private.

Package-private access

A class without public is visible only inside its package. Here PriceRules is an internal detail of the shop.model package: Product uses it, but code outside cannot:

// src/shop/model/PriceRules.java
package shop.model;
 
class PriceRules {
    static double round(double price) {
        return Math.round(price * 100) / 100.0;
    }
}

Private fields are truly closed too. If you write IO.println(tea.title); in Main, the compiler replies:

Main.java:5: error: title has private access in Product
    IO.println(tea.title);
                  ^

In a single file, as in the previous lessons, there would be no such error: there all classes are nested in one implicit class.

Building and running

The project looks like this: the src folder holds Main.java and shop/model/ with two classes. Since Java 22 you can run it straight from the sources — Java finds and compiles the files it needs by their package names:

cd src
java Main.java

The classic way is to compile everything with javac into the out folder first, and then run the compiled .class files, telling Java where to find them (-cp, the classpath):

cd src
javac -d ../out Main.java shop/model/*.java
java -cp ../out Main

Output in both cases:

Tea: 4.5 €

Large projects are built with Maven or Gradle: they do the same thing and also download libraries. The code there lives in the src/main/java folder. An even larger unit of organisation than packages — modules with a module-info.java file — is covered in the Modules lesson.

Common mistake

A class without public cannot be used from another package. If Main refers to PriceRules directly — shop.model.PriceRules.round(4.499) — the build stops:

Main.java:4: error: PriceRules is not public in shop.model; cannot be accessed from outside package
    IO.println(shop.model.PriceRules.round(4.499));
                         ^

Either make the class public if it is really needed outside, or give access through a public method of another class, like getPrice() in Product.

Thanks for reading!

Donate to the site — we work hard for you.