Что такое classpath java
Перейти к содержимому

Что такое classpath java

  • автор:

Classpath

В большинстве случаев команды java и javac должны найти другие классы необходимые для компиляции и выполнения. Самый распространенный случай — это использование классов входящих в Java SE. Или, например, нам нужно скомпилировать и запустить класс, который использует другие классы, не входящие в Java SE.

Команды java и javac используют следующий алгоритм поиска:

  1. Они используют один и тот же список каталогов, в которых ищут необходимые файлы.
  2. Обе команды в процессе поиска просматривают список каталогов в одном и том же порядке.
  3. Как только необходимый класс найден, процесс поиска прекращается. Если список каталогов содержит два или более классов с одним и тем же именем, используется первый найденный.
  4. Первое место используемое в процессе поиска — это каталоги содержащие классы Java SE.
  5. Второе место — каталоги определенные в так называемом Сlasspath.

Classpath может быть задано двумя способами:

  1. Как переменная окружения CLASSPATH. Команды java и javac используют этот способ по умолчанию.
  2. Как ключ -classpath (или -cp) команд java и javac. Этот способ переопределяет список каталогов заданный переменной окружения, но только для конкретного вызова. Данный метод является более предпочтительным.

Способы задания Classpath Фото

2. Использование ключа -classpath

Рассмотрим использование ключа -cp используя классы first.Example1 и second.Example2 , описанные здесь. Но предположим, что класс second.Example2 находится в другом проекте и доступны только его .class файлы. На рисунке изображена схема каталогов для данного примера:

Структура каталогов фото

Следующая команда будет использована для компиляции first.Example1 класса, где ключ -cp указывает на расположение .class файла second.Example2 :

cd projectExample1 javac -d classes -cp ../projectExample2/classes src/first/Example1.java 

Для запуска программы используется команда:

cd projectExample1 java -cp classes;../projectExample2/classes first.Example1

Ключ -cp указывает расположение .class файла second.Example2 (как и при компиляции), а также путь для поиска .class файла first.Example1 — classes.

Несколько важных правил при использовании ключа -cp :

  1. Ключ -cp может содержать несколько каталогов, разделенных точкой с запятой, как показано в примере при запуске команды java .
  2. Если указывается подкаталог, это НЕ означает что родительский каталог тоже входит в classpath. Например, для ключа -cp ../projectExample2/classes , каталог ../projectExample2 не будет входить в classpath.
  3. Если используется ключ -cp , то команды javac и java НЕ ищут классы в текущем каталоге по умолчанию. Для указания текущего каталога используется точка. Например:

cd projectExample1/classes java -cp .;../../projectExample2/classes first.Example1​

Презентацию с видео можно скачать на Patreon .

Что такое classpath?

Classpath – это параметр, который указывает приложениям где искать пользовательские классы. По этому адресу должны быть найдены все классы, для которых не применяются специальные загрузчики. На место поиска стандартных классов JRE этот параметр не влияет.

Кроме непосредственно Java-приложений (команда java ), этот параметр применим и для других утилит JDK, таких как javac , javadoc и другие.

Есть два основных способа установки classpath: в переменной окружения ОС CLASSPATH , и в аргументе командной строки -cp (синоним -classpath ). Второй способ предпочтительнее, потому что позволяет устанавливать разные значения для разных приложений. Значение по умолчанию – текущая директория.

В параметре передаются пути к jar-файлам и корневым директориям с пакетами. Пути разделяют символом : в параметре командной строки, или же ; в переменной окружения. Чтобы включить все файлы директории, разрешается использовать в конце пути символ * .

Если приложение запускается из jar-файла ( java -jar ), classpath должен быть указан в его манифесте.

Pro Java

Теперь быстренько разберемся classpath, так как это достаточно важная тема для разработки на Java. Естественно я тут не смогу разобрать все тонкости и хитрости, но постараюсь представить самое необходимое чтобы было понимание этой темы. Для желающих разобраться глубже приведу линки для самостоятельного изучения. Ну и как всегда гугль в помощь.

Чтобы понимать что происходит под капотом у любой Java IDE когда она собирает проект и запускает его надо хоть немного попрактиковаться в использовании компилятора javac, среды исполнения java и понять classpath.

По существу classpath указывает компилятору или виртуальной машине где искать классы необходимые для сборки проекта или же его запуска. Немного об этом мы уже узнали тут. Теперь разберемся с этим получше.

Указать где компилятору или виртуальной машине искать классы можно через ключ –classpath или же системную переменную окружения CLASSPATH. Мы рассмотрим оба этих варианта.

Начнем с простого. Вернемся к нашему проекту Hello World (00004E_HelloWorld), там где мы разделили его на два файла Hello.java и Word.java.

Теперь попробуем создать исполняемый (jar) файл этого проекта из среды Eclipse. Так как скомпилированные, читай готовые к исполнению, файлы в Java имеют расширение class, а классов в реальных программах, могут быть сотни и тысячи, то их собирают в один или несколько jar архивов и таким образом запускают. То есть уже существует не россыпь файлов с расширением class, а один или несколько jar файлов.

И так! Понеслась! Воспользуемся Export для создания jar

CP0001

CP0003

После этого мы получим файл HelloWorld.jar готовый к исполнению на виртуальной машине java. Запустим его из командной строки:

CP0004

Запускать jar файлы надо с ключом –jar как показано на скрине выше. Если этот ключ не использовать то вылетит ошибка:

CP0005

Нам сообщили что не знают где искать главный (main) класс для HelloWorld.jar. Но запустить все же можно и без ключа –jar, но уже воспользовавшись на ключом –classpath , для которого существует сокращенный вариант –cp . Вот как это можно сделать:

CP0006

Почему строчка запуска выглядит именно так? Вспоминаем что именно класс Hello.java содержит у нас метод main.

CP0007

Класс Word.java такого метода не имеет.

CP0008

Как я уже говорил метод main – это точка входа в программу, то есть место от куда начинается ее выполнение и поэтому виртуальной машине java надо знать, от куда надо начинать выполнять программу. Если она не может найти метод main, то она начинает ругаться, как это было показано выше.

И так в нашей строчке

java -cp HelloWorld.jar Hello

мы указали что искать метод main надо в классе Hello (расширение .class опускается) по пути HelloWorld.jar. Jar и zip архивы рассматриваются виртуальной машиной как каталоги, поэтому их надо указывать по полному имени с расширением.

Теперь скомпилируем наши классы Hello.java и Word.java самостоятельно из командной строки без помощи Eclipse, чтобы еще глубже понять как все работает. Для чистоты эксперимента рекомендую удалить все файлы с расширением .class и .jar из каталога bin.

Для начал просто скомпилируем исходники в class файлы без упаковки их в jar, чтобы было понятнее.

Переходим в коневой каталог 00004E_HelloWorld и от туда даем команду компиляции

javac -encoding utf8 -d bin src\Hello.java src\Word.java

CP0009

Поскольку у нас программа состоит из двух классов Hello и Word, то их обоих сразу надо указать компилятору. Кроме того так же надо указать и кодировочку исходников. Так же мы указали папку bin – это то куда будут складываться откомпилированные файлы.

Теперь у нас в каталоге bin два файла Hello.class и Word.class. Перейдем в него чтобы запустить программу.

CP0010

Все работает. Но файлики у нас там лежат россыпью классво .class

Теперь упакуем эти файлики .class в jar архив командой

jar cf HelloWorld.jar Hello.class Word.class

и попробуем запустить HelloWorld.jar

CP0012

И вылетела ошибочка. Почему так? Ведь у нас уже есть jar файл в который упакованы оба класса.

CP0013

Но все равно не работает. Это происходит потому, что внутри jar файла мы не указали какой файл у нас имеет метод main.

Запустить наш jar файл все таки можно указав дополнительно, какой класс содержит метод main.

java -cp HelloWorld.jar Hello

CP0014

Теперь все работает. Но согласитесь так запускать jar файл не удобно, так как всегда надо знать какой класс содержит метод main. Если вы смотрели внимательно, то видимо заметили внутри архива HelloWorld.jar папку META-INF. В ней содержится файл MANIFEST.MF

CP0015

Вот в нем и должна содержаться информация о классе содержащем метод main, но пока в нем ее нет.

CP0016

Исправим эту ошибочку. Удалим файлик HelloWorld.jar и создадим его заново, но уже с добавлением информации о классе содержащим метод main. Сделаем это следующей командой

jar cfe HelloWorld.jar Hello Hello.class Word.class

И запустим файл HelloWorld.jar уже как полагается без танцев с бубном.

CP0017

Как видим все работает нормально. Это произошло потому, что файл MANIFEST.MF уже содержит информацию о классе содержащем метод main.

CP0018

Ну вот теперь мы имеем хоть какое-то представление о том что происходит когда какая-либо IDE создает исполняемый jar файл, а так же получили представление о classpath. В следующей статье мы немного углубим его.

P.S. Так же стоит знать что по умолчанию для виртуальной машины java доступны все классы стандартной библиотеки java, а так же все классы в текущем каталоге от куда запускается главный класс содержащий метод main.

Ну и на последок ссылка где про classpath рассказано достаточно подробно. Правда я не знаю как долго она проживет.

coreer

Это пример теоретического принципа динамической линковки библиотек в разработке ПО для java-платформы.
Суть в том, что библиотеки(вернее пакеты целиком или контектные классы) указанные в класспазе, загружаются только тогда, когда это нужно в конкретном месте выполнения приложения.

Вирутальная машина ищет и загружает библиотеки в следующем порядке(это типы библиотек):
1) Классы этапа загрузки — это библиотеки в которых непосредственно нуждается сама платформа java.
2) Классы из JAVA_HOME/jre/lib/ext.
3) Другие библиотеки.

Если первые две библиотеки виртуальная машина сама понужде знает откуда загружать, то вот последние библиотеки непонятно откуда брать.

Для этого нам и нужно пользоваться переменной CLASSPATH. Устанавливать ее мы можем в следующих местах:
1) В глобальных пременных ОС (либо для всех сессий входа в ОС, либо только для поточной сессии).
2) Дополнительным аргументом в утилите cli java.
3) В манифесте jar-архива.

Примеры:
№ 1
У нас есть структура каталогов

/home/user/myprogram/ 
|
---> org/
|
---> mypackage/
|
---> HelloWorld.class
---> SupportClass.class
---> UtilClass.class

Класс HelloWorld — это главный класс приложения.
Если мы находимя в каталоге myprogram, то можем вызвать просто:

java org.mypackage.HelloWorld

Если же мы находимся в любом другом месте, то

java -classpath /home/user/myprogram org.mypackage.HelloWorld
D:\myprogram\ 
|
---> lib\
|
---> supportLib.jar
|
---> org\
|
--> mypackage\
|
---> HelloWorld.class
---> SupportClass.class
---> UtilClass.class
java -classpath D:\myprogram;D:\myprogram\lib\supportLib.jar org.mypackage.HelloWorld
set CLASSPATH=D:\myprogram;D:\myprogram\lib\supportLib.jar
java org.mypackage.HelloWorld

Интересность 1
Можно заметить, что в предыдущих примерах мы переопределяем класспаз для контретного ява-вызова полсностью, тоесть если какие-то библиотеки указаны в глобальной ОС переменной, то они будут перетерты под конкретный вызов. Если же нужно сохранить и эти места библиотек, нужно еще и указать через разделитель(в юникс-системах “:”, в виндовсе “;”) точку “.” Можно увидеть пример в примере следующей интересности.

Интересность 2
Если у нас есть много библиотек запакованных в jar-архивы, которые находятся в одной директории, то мы с версии платформы java 6 можем указать *, и все эти архивы окажутся в класспазе, а не перечислять каждый архив отдельно:

java -classpath ".;c:\mylib\*" MyApp

Интересность 3
Вот так можно узнать какой класспаз в данный момент выполнения приложения:

System.getProperty("java.class.path");

№ 3
Пример с архивом:

D:\myprogram\ 
|
---> helloWorld.jar
|
-----------> lib\
|
---> supportLib.jar
---> supportLib2.jar

В манифесте должно быть:

Main-Class: org.mypackage.HelloWorld
Class-Path: lib/supportLib.jar lib/supportLib2.jar

В таком случае мы можем вызывать так:

java -jar D:\myprogram\helloWorld.jar

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *