Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Пакеты и модификаторы доступа

Пока программа помещается в один файл, порядок в ней держать легко. Настоящие проекты состоят из сотен классов, и их раскладывают по пакетам. Пакеты вместе с модификаторами доступа решают, какой код кому виден.

Пакет — это папка

Пакет — именованная группа классов. Первая строка файла package shop.model; говорит, что класс лежит в пакете shop.model, и файл обязан находиться в папке shop/model. В проекте каждый открытый класс живёт в своём файле с тем же именем:

// 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);
    }
}

Имена пакетов пишут строчными буквами через точку. Полное имя класса включает пакет: shop.model.Product.

import

Чтобы пользоваться классом из другого пакета, его импортируют — после этого достаточно короткого имени. Главный файл может оставаться компактным, с void main():

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

Классы из пакета java.lang — String, Math, Integer — доступны всегда. В компактном файле вроде этого автоматически импортированы и остальные пакеты модуля java.base, например java.util — поэтому в примерах учебника List и Map работали без import. В классических файлах с package их нужно импортировать: import java.util.List;.

Четыре уровня доступа

Модификатор перед классом, полем или методом определяет, откуда к нему можно обратиться:

МодификаторКому доступно
publicвсем
protectedсвоему пакету и подклассам в любом пакете
без модификаторатолько своему пакету
privateтолько своему классу

Доступ без модификатора называют пакетным (package-private). Обычное правило: поля — private, методы для внешнего мира — public, всё вспомогательное — без модификатора или private.

Пакетный доступ

Класс без public виден только внутри своего пакета. Здесь PriceRules — внутренняя деталь пакета shop.model: Product им пользуется, а код снаружи — нет:

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

Закрытые поля тоже по-настоящему закрыты. Если в Main написать IO.println(tea.title);, компилятор ответит:

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

В одном файле, как в прошлых уроках, такой ошибки не было бы: там все классы вложены в один неявный класс.

Сборка и запуск

Проект выглядит так: в папке src лежат Main.java и shop/model/ с двумя классами. Начиная с Java 22, запускать его можно прямо из исходников — Java сама найдёт и скомпилирует нужные файлы по именам пакетов:

cd src
java Main.java

Классический способ — сначала скомпилировать всё командой javac в папку out, а потом запустить готовые .class-файлы, указав, где их искать (-cp, classpath):

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

Результат в обоих случаях:

Чай: 4.5 €

Большие проекты собирают инструментами Maven или Gradle: они делают то же самое и заодно скачивают библиотеки. Код там лежит в папке src/main/java. А ещё более крупный уровень порядка, чем пакеты, — модули с файлом module-info.java — разобран в уроке Модули.

Частая ошибка

Класс без public нельзя использовать из другого пакета. Если в Main обратиться к PriceRules напрямую — shop.model.PriceRules.round(4.499), — сборка остановится:

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));
                         ^

Либо сделайте класс public, если он действительно нужен снаружи, либо дайте доступ через открытый метод другого класса, как getPrice() в Product.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.