При создании программ на Java мы так или иначе работаем с классами. Какие-то какие-то созданы непосредственно нами, а какие-то классы созданы другими разработчиками, и мы хотми подключить эти классы себе в программу. Эти классы могут быть доступны в виде файлов с
расширением .class, либо в виде архивов jar. И в данном случае мы можем столкнуться с проблемой установки путей к этим классам: куда нам надо поместить эти файлы или как указать компилятору/среде выполнения,
что мы хотим использовать именно эти файлы.
Многие распространенные инструменты разработки и сборки, как например, среды разработки IDE, имеют свои механизмы управления путями к классам. Однако разработчик при необходимости может задать пути к классам вручную. Поэтому рассмотрим, как мы можем управлять путями к классам Java.
Подключаемые классы могут распространяться в виде отдельных файлов с расширением .class или в качестве библиотеки в виде jar-файла.
Путь к файлам .class представляет путь к папке. Причем файлы располагаются с учетом из пакетов. Например, в качестве примера создадим в системе папку
/home/user/classdir (на Linux) или c:\classdir (на Windows)
Пусть у нас есть следующий класс Person
package com.metanit;
public class Person
{
String name;
public Person(String name){
this.name = name;
}
public void print() {
System.out.printf("Person %s\n", name);
}
}
Этот код компилируется в файл Person.class. Поскольку этот класс принадлежит пакету "com.metanit", соответственно полное название класса "com.metanit.Person".
Поэтому этот класс помещается в подкаталог /home/user/classdir/com/metanit/Person (на Linux) или c:\classdir\com\metanit\Person (на Windows). То есть при размещении классов
мы учитываем пакеты класса и проецируем эти пакеты на структуру каталогов.
Путь к классам внутри .jar- файла представляет путь к самому .jar- файлу. Например, возьмем в качестве примера папки для jar-файла папку
/home/user/jardir (на Linux) или c:\jardir (на Windows).
Пусть в этой папке у нас располагается библиотека mathlib.jar. В этом случае путь к ее классам этой библиотеке будет путь:
/home/user/jardir/mathlib.jar (на Linux)
c:\jardir\mathlib.jar (на Windows)
Путь к классам — это совокупность всех расположений, где могут находиться файлы классов. То есть может быть место (допустим, папка classdir), где храняться по отдельности скомпилированные классы, например:
// Linux /home/user/classdir // Windows c:\classdir
И также отдельно по другому пути могут располагаться библиотеки jar. Например, у нас есть библиотека "mathlib.jar" по следующему пути:
// Linux /home/user/jardir/mathlib.jar // Windows c:\jardir\mathlib.jar
В этом случае общий путь к классам будет содержать оба этих подпути. Формат пути к классам следующий:
// Linux путь1:путь2:путь3:путьN // Windows путь1;путь2;путь3;путьN
Все подпути к классам перечисляются друг за другом и отделяются друг от друга разделителем. В Linux таким разделителем является двоеточие (":"), а в Windows - точка с запятой (";").
Кроме конкретных путей к классам мы можем использовать специальные относительные пути, например, "." (путь к текущей папке), ".." (путь к родительскому каталогу) и т.д.
И если перейти непосредственно к нашим классам, то мы можем определить пути к классам следующим образом:
// Для Linux /home/user/classdir:.:/home/user/jardir/mathlib.jar // Windows c:\classdir;.;c:\jardir\mathlib.jar
То есть в данном случае для хранения классов мы будем использовать три подпути:
Базовый каталог "/home/user/classdir" или "c:\classdir"
Текущий каталог (представляет символ точка = ".")
Путь к jar - "/home/user/jardir/mathlib.jar" или "c:\jardir\mathlib.jar"
Стоит отметить, что у нас может быть несколько jar-файлов, которые мы хотим использовать. В этом случае при определении пути можно использовать символ подстановки, чтобы указать каталог для произвольного количества JAR-файлов, например:
// Unix/Linux - символ * необходимо экранировать, чтобы предотвратить расширение командной оболочкой /home/user/classdir:.:/home/user/jardir/'*' // Windows c:\classdir;.;c:\jardir\*
Теперь посмотрим, как мы можем установить этот путь непосредственно при компиляции/выполнения программы.
Прежде всего пути к классам управляются через переменную окружения CLASSPATH, которая обычно добавляется в систему при установке JDK. Обычно в качестве путей к файлам классов применяются текущий и родительский каталог. Например, выведем значение этой переменной на консоль:
eugene@Eugene:~$ echo $CLASSPATH .:.. eugene@Eugene:~$
В моем случае вывод показывает следующую строку ".:..". В данном случае первая точка "." указывает на текущий каталог, а последние две точки ".." на родительский каталог. Двоеточие между ними служит в качестве разделителя между путями. То есть в данном случае переменная CLASSPATH содержит два пути: текущий и родительский каталог.
Таким образом, мы можем поместить файлы в текущий или в родительский каталог, и компилятор/среда выполнения их найдут.
Обычно не рекомендуется менять глобальные настройки. И тогда при работе мы можем задать пути на время работы консоли. Установка переменной окружения CLASSPATH в данном случае зависит от конкретной оболочки и системы:
// Для Linux (bash) export CLASSPATH=/home/user/classdir:.:/home/user/jardir/mathlib.jar // Windows set CLASSPATH=c:\classdir;.;c:\jardir\mathlib.jar
Путь к классам сохраняется до завершения работы оболочки. Таким образом, мы сохраним начальное значение переменной CLASSPATH. С другой стороны, в следующий раз при работе с Java, нам потребуется снова устанавливать
эту переменную.
Самый простой способ установки пути к классам заключается в установке параметра -classpath (или -cp, или более современного варианта
--class-path). При чем этот параметр действует как при компиляции с помощь. javac, так и при выполнении программы с помощью утилиты java:
// Для Linux javac -classpath /home/user/classdir:.:/home/user/jardir/mathlib.jar Program.java java -classpath /home/user/classdir:.:/home/user/jardir/mathlib.jar Program // Windows javac -classpath c:\classdir;.;c:\jardir\mathlib.jar Program.java java -classpath c:\classdir;.;c:\jardir\mathlib.jar Program
Вся команда должна быть набрана в одну строку.
Как происходит поиск файлов и классов?
Если вы в коде программы используете класс, не указывая его пакет, компилятору сначала необходимо найти пакет, содержащий данный класс. Для этого компилятор просматривает все директивы импорта как возможные
источники расположения этого класса. Предположим, в коде используется некоторый класс com.metanit.Person, и компилятору надо найти путь при компиляции следующей программы:
import java.util.*;
import com.metanit.*;
class Program{
public static void main(String[] args) {
Person tom = new Person("Tom");
tom.print();
}
}
Данный исходный файл содержит две директивы импорта:
import java.util.*; import com.metanit.*;
В этом случае компилятор пытается найти классы java.lang.Person (поскольку пакет java.lang всегда импортируется по умолчанию),
java.util.Person, com.metanit.Person и Person в текущем пакете. Компилятор ищет каждый из этих классов во всех местах пути к классам,
в частности, пути, которые установлены с помощью переменной CLASSPATH и параметра -classpath. При этом порядок директив импорта или поиска не имеет значения,
так как имена классов должны быть уникальными. А если будет найдено более одного класса, возникнет ошибка компиляции.
Кроме того, компилятор также проверяет исходные файлы, чтобы определить, является ли исходный файл более новым, чем файл класса. В этом случае исходный файл автоматически перекомпилируется.
Предположим, виртуальная машина ищет файл класса com.metanit.Person. Сначала она просматривает стандартные классы API Java.
Там класс не найден, поэтому она обращается к пути к классам. Допустим, путь к классам установлен на "/home/user/classdir:.:/home/user/jardir/mathlib.jar"
Используя эти пути виртуальная машина ищет следующие файлы:
/home/user/classdir/com/metanit/Person.class
com/metanit/Person.class в текущем каталоге
com/metanit/Person.class в архиве /home/user/jardir/mathlib.jar
Компилятор Javac всегда ищет файлы в текущем каталоге, но модуль запуска виртуальной машины Java ищет файлы в текущем каталоге только в том случае, если каталог "." присутствует в пути к классам.