Знание основ программирования и потока выполнения программных файлов помогает нам понять язык. Знание параметра
Classpath это одно из основных понятий, которым должен владеть каждый Java-разработчик. Сегодня мы обсудим, что такое путь к классам (
Classpath), как его установить и как он помогает JVM исполнять файлы классов. Если совсем коротко: classpath это список папок и архивов, в которых
javac и
java ищут файлы классов. Задают его флагом
-cp при запуске, переменной окружения
CLASSPATH или, что бывает чаще всего, системой сборки вроде Maven и Gradle.
Что такое Classpath?
Classpath является одним из основных параметров в Java, однако новички в программировании часто понимают его неправильно. Если упростить, то
Classpath это просто
набор путей, по которым компилятор Java и JVM должны находить необходимые классы для компиляции или выполнения других классов.
Кратко
- Classpath это список папок, jar- и zip-архивов, в которых javac и java ищут файлы классов.
- Задать его можно флагом -cp (он же -classpath и --class-path) или переменной окружения CLASSPATH, причем флаг всегда перекрывает переменную.
- Если не задано ничего, classpath равен текущей папке, поэтому запуск из каталога с классами работает будто сам собой.
- Несколько путей перечисляют через разделитель: точка с запятой в Windows, двоеточие в Linux и macOS.
- Чтобы не перечислять библиотеки по одной, в элементе пути пишут звездочку: lib/* подхватит все jar-файлы из папки.
- В рабочих проектах classpath собирают IDE и системы сборки по описанию зависимостей, руками его почти не трогают.
![Машина едет по лесной дороге в сумерках: путь, по которому JVM ищет классы]()
Как Classpath помогает JVM в выполнении файлов классов
Давайте начнем с примера. Предположим, что у нас есть файл
Main.java, который находится в папке
/Users/vikram/Documents/test-java/src/com/programming/v1/Main.java.
package com.programming.v1;
public class Main {
public static void main(String[] args) {
System.out.println("Hello classpath");
}
}
Допустим, мы находимся в
/Users/vikram/Documents и хотим скомпилировать этот класс (если на этом шаге компилятор не находит классы пакета, разбор частых причин есть
в отдельной статье):
javac test-java/src/com/programming/v1/Main.java
Кстати, ради одного файла отдельная компиляция с Java 11 уже не обязательна: команда
java test-java/src/com/programming/v1/Main.java запустит исходник сразу (
JEP 330). Файл при этом, как сказано в
документации, компилируется в память, и
.class на диске не появляется, так что для разбора classpath такой режим нам не подходит. Возвращаемся к обычному пути.
Теперь, чтобы выполнить этот файл класса, нам нужно сообщить виртуальной машине Java, где искать файл
.class, используя
classpath или флаг
cp в команде
java.
vg@lp1 Documents % java -cp "test-java/src" com.programming.v1.Main
Hello classpath
vg@lp1 Documents % java -classpath "test-java/src" com.programming.v1.Main
Hello classpath
Первый параметр это корневая папка, в которую записывается пакет. Второй параметр это имя пакета с именем класса. Когда команда Java исполняется, виртуальная машина Java просматривает папку
test-java/src, а затем загружает основной класс для ее выполнения. Подробно этот этап разобран в статье про
загрузку классов в JVM.
Важное замечание о разнице между ОС: ⚠️
Если вам нужно указать несколько путей, их разделитель зависит от операционной системы (это правило описано в
документации команды java):
- В Windows используется точка с запятой (;). Пример: "lib/library.jar;build/classes"
- В Linux и macOS используется двоеточие (:). Пример: "lib/library.jar:build/classes"
Как установить переменную CLASSPATH
Переменную окружения
CLASSPATH на компьютерах под управлением Linux устанавливают так:
export CLASSPATH="test-java/src"
Classpath на компьютере с Windows можно добавить/обновить с помощью переменных среды.
После того, как переменная среды установлена, команду
java можно выполнить, как показано ниже:
vg@lp1 Documents % java com.programming.v1.Main
Hello classpath
Автоматическое управление classpath
Ручное управление
classpath это отличный способ понять, как все работает "под капотом". Однако в реальных проектах такой подход почти не используется, так как современные приложения могут иметь десятки или даже сотни зависимостей (сторонних библиотек).
Сегодня
classpath управляется автоматически с помощью:
- IDE (Integrated Development Environment): Среды разработки, такие как IntelliJ IDEA, Eclipse или VS Code, автоматически формируют и управляют classpath для вашего проекта. Вы просто добавляете библиотеки в настройки проекта, а IDE делает все остальное.
- Системы сборки (Build Tools): Инструменты, такие как Maven и Gradle, являются стандартом в индустрии. Вы описываете все необходимые зависимости вашего проекта в специальном файле (
pom.xml для Maven или build.gradle для Gradle), и система сборки сама скачивает нужные .jar-файлы и подключает их в classpath во время компиляции и запуска. Как это выглядит на практике, показано в статье про подключение библиотек с помощью Maven.
Этот автоматизированный подход позволяет избежать ошибок и значительно упрощает работу с большими и сложными проектами.
Итого, взяться classpath может из четырех мест:
| Откуда берется classpath |
Как выглядит |
Когда так делают |
| Флаг -cp, -classpath или --class-path |
java -cp "lib/*:build/classes" com.example.Main |
разовый запуск или сборка; перекрывает переменную окружения |
| Переменная окружения CLASSPATH |
export CLASSPATH="build/classes" |
действует на все запуски в сессии, поэтому легко забыть про нее и долго искать причину |
| Ничего не задано |
classpath равен текущей папке (.) |
учебный запуск из каталога, где лежат классы |
| IDE и системы сборки |
зависимости описаны в pom.xml или build.gradle |
обычные рабочие проекты: путь собирается автоматически |
Когда classpath не работает
Почти все проблемы с путем к классам сводятся к четырем ситуациям:
- Запуск не из той папки. Без флага и без переменной окружения classpath равен текущему каталогу, поэтому из Documents команда java com.programming.v1.Main класс не найдет, а из test-java/src найдет.
- Библиотека не попала в путь. При обращении к ее классу вы получите ClassNotFoundException или NoClassDefFoundError. Проверьте, что нужный jar перечислен в -cp, и помните, что звездочка lib/* забирает архивы только из самой папки, но не из вложенных.
- Перепутан разделитель. В Windows элементы пути разделяет точка с запятой, и двоеточие там не подойдет: оно уже занято буквой диска в путях вроде C:\lib\app.jar.
- Запуск архива через -jar. В документации команды java сказано прямо: если указан -jar, источником всех классов приложения становится сам архив, а остальные настройки classpath игнорируются. Нужные библиотеки в этом случае перечисляют в заголовке Class-Path манифеста или собирают все в один fat jar.
Заключение
Понимание
CLASSPATH это фундаментальное знание для любого Java-разработчика. Оно объясняет, как JVM находит и связывает классы во время выполнения. Хотя сегодня этот процесс почти всегда автоматизирован с помощью IDE и систем сборки вроде Maven или Gradle, знание основ поможет вам лучше понимать свои инструменты и решать возможные проблемы.
Вопросы и ответы
Что такое classpath в Java простыми словами?
Это список мест, где Java ищет скомпилированные классы: папок, jar- и zip-архивов. Компилятор берет оттуда классы, на которые ссылается ваш код, а виртуальная машина ищет там же классы во время выполнения. Classpath легко спутать с системной переменной
PATH, но это разные вещи:
PATH говорит операционной системе, где лежат исполняемые файлы вроде
java.exe, а classpath говорит уже самой Java, где лежат классы.
Чем флаг -cp отличается от переменной окружения CLASSPATH?
Областью действия. Флаг задается на один конкретный запуск и, как сказано в документации команды
java, перекрывает любое значение переменной. Переменная же действует на все запуски в текущей сессии или у всей системы, поэтому она и считается источником трудноуловимых ошибок: программа работает у вас и не работает у коллеги. В скриптах и сборках предпочитают явный флаг.
Что будет, если classpath не задавать вообще?
Java будет искать классы в текущей папке. В документации это сформулировано прямо: если флаг не использован и переменная не задана, пользовательский classpath состоит из текущего каталога. Отсюда и типичная картина: из папки с
Main.class программа запускается, а на шаг выше уже нет, потому что текущая папка стала другой.
Как добавить в classpath сразу несколько библиотек?
Перечислить их через разделитель, свой для каждой системы: точка с запятой в Windows и двоеточие в Linux и macOS. Если библиотек много, вместо перечисления ставят звездочку: элемент
lib/* означает все файлы с расширением jar из этой папки. Учтите две тонкости: звездочка не заходит в подпапки и не гарантирует порядок, в котором архивы попадут в путь.
Почему возникает ClassNotFoundException и при чем тут classpath?
Потому что класс ищут по имени во время выполнения, а в classpath его нет: забыли добавить библиотеку, ошиблись в пути или перепутали каталог запуска. Рядом живет похожая ошибка
NoClassDefFoundError, и разница между ними полезная: первая означает, что класс не нашли по строковому имени, а вторая, что при компиляции класс был, а при запуске его определение не подгрузилось. Лечится обе одинаково: проверить, что нужный jar или каталог действительно попал в путь.
Чем classpath отличается от module path?
Module path появился в Java 9 вместе с системой модулей. На classpath все классы сваливаются в общую кучу без границ, а модульный путь работает с модулями, каждый из которых в файле
module-info.java объявляет, от кого зависит и какие пакеты отдает наружу. Задается он флагом
--module-path (или
-p). Classpath никуда не делся: код без модулей по-прежнему запускается через него.
Читайте также: