Назад Зміст Вперед

Лабораторна робота: «Використання опції – classpath для компіляції програми, де задіяно об'єкти класів, що розміщені у файлах з різних директорій»

Вказівка інтерпретатору, де шукати класи
Інтерпретатору треба знати усі місця, де він може знайти класи. Що є таким місцем? Директорія і/або бібліотека -jar- файл. Зверніть увагу - саме файл. Інакше кажучи, якщо у вас файл javaee.jar знаходиться в директорії E :\java\lib\ - інтерпретатору потрібний повний шлях до файлу, а саме - E:\java\lib\javaee.jar. Простої вказівки директорії НЕДОСТАТНЬО!

Спосіб 1. Змінна оточення CLASSPATH

Задається змінна оточення CLASSPATH, і в ній через роздільник (';' для Win, ':' для *NIX) прописуються усі повні шляхи до файлів бібліотек і до директорій, в яких лежать дерева класів. Зверніть увагу, що директорія - це точка, в якій лежить КОРІНЬ усіх скомпільованих класів. Тобто, якщо класи з пакету mypackage.test компілювалися в директорію c:\myproject\classes, то в CLASSPATH повинна фігурувати саме c:\myproject\classes, а не c:\myproject\classes\mypackage і не c:\myproject\classes\mypackage\test.

Спосіб 2. Вказівка ключа - classpath інтерпретатору (компілятору)

Я можу вказати інтерпретатору рівно ті бібліотеки, які мені потрібні. І рівно ті джерела коду, з яких він цей код повинен брати. Не більше і не менше.
Приклад. Припустимо, у мене в проектній директорії є піддиректорія classes, в якій знаходяться скомпільовані класи, і піддиректорія lib, в якій лежать бібліотеки velocity -1.4.jar і log4j - 1.2.8.jar. Тоді командний рядок для запуску мого класу ua.skipy.myproject.Main виглядатиме так:
java -classpath ./classes;./lib/velocity-1.4.jar;./lib/log4j-1.2.8.jar ua.skipy.myproject.Main
За пунктами: я вказую інтерпретатору, що класи потрібно шукати в директорії ./classes ('.' - поточна директорія), у бібліотеці ./lib/velocity - 1.4.jar і у бібліотеці ./lib/log4j -1.2.8.jar, в порядку їх перерахування.
Якщо ж мені не треба використовувати зовнішні бібліотеки, то командний рядок перетворюється на наступний:
java -classpath ./classes ru.skipy.myproject.Main
Зверніть увагу на - classpath ./classes. Відсутність classpath в параметрах інтерпретатора є джерелом великої кількості проблем.

Спосіб 3. Директорія <JRE _ INSTALLATION _ DIRECTORY>/lib/ext

Придатний тільки для підключення jar- файлів. Файл кладеться у вказану директорію. Все. При старті віртуальної машини бібліотека підключається. Його варто використовувати, коли треба щось поставити на клієнтську машину, де є всього одна JRE (і те якщо є).
Що буде, якщо не вказати classpath, ні в якості змінної оточення, ні в якості параметра інтерпретатору? Буде усім відома помилка:
Exception in thread "main" java.lang.NoClassDefFoundError: … 
Замість '...' пишеться ім'я класу, який віртуальна машина не змогла знайти. Помилка ця означає, що визначення класу не знайдене. Під визначенням класу віртуальна машина розуміє його байт-код. Тобто, вона просто не змогла знайти потрібний файл.

Лабораторна робота
Пишемо програму Hello, World!


Крок 1. Створення структури директорій

Єдине допущення - ми знаходимося в директорії-корені проекту HelloWorld.
mkdir src
mkdir classes
cd src
mkdir mypackage
cd ..
Створили директорію для початкових файлів - src. Створили директорію для скомпільованих файлів - classes. Створили усередині src директорію, що відповідає імені пакету, - mypackage.


Крок 2. Створення початкового файлу 

В директорії src/mypackageстворюємо початковий файл - HelloWorld.java: 
package mypackage;
public class HelloWorld{
    public static void main(String args[]){
System.out.println("Hello, World!");
    }
}

Крок 3. Компіляція 
Зверніть увагу, в командному рядку ми знаходимося в корені проекту! 
Команда компіляції: 
javac -classpath ./classes -d ./classes src/mypackage/HelloWorld.java
Зверніть увагу на ключ - d. Цей ключ вказує компілятору, де знаходиться корінь для скомпільованих класів. Якщо не вказати його, коренем вважатиметься поточна директорія. При компіляції декількох класів в пакеті одночасно можна замість імені конкретного файлу вказати *.java. 
В результаті компіляції в директорії ./classesстворюється піддиректорія mypackage, в яку поміщається файл HelloWorld.class.

Крок 4. Виконання програми 
java -classpath ./classes   mypackage.HelloWorld
Ім'я класу вказується разом з пакетом, ОБОВ'ЯЗКОВО! І вказується саме ім'я класу, а не файлу! Тобто, .class у кінці додавати не потрібно. 
Спеціально розпишу логіку пошуку файлу з байт-кодом:  Усі точки в повному імені класу замінюються на роздільники - '/'. До отриманого рядка приписується .class. Файл шукається у бібліотеках і вказаних директоріях із скомпільованими класами в порядку їх вказівки. Файл шукається за отриманим на минулому кроці відносним шляхом. Тобто, ім'я класу mypackage.HelloWorld перетвориться у відносний шлях до файлу mypackage/HelloWorld.class. Віртуальна машина знаходить файл по цьому відносному шляху в директорії ./classes.

Крок 5. Створення архіву (jar- файлу) 
Збираємо архів, який можна запускати за допомогою команди java, - jar <ім'я архіву>. Спершу створюємо файл manifest.mf, в якому буде вказаний головний виконуваний клас: 
Manifest-Version: 1.0
Created-By: 1.6.0_19 (Sun Microsystems Inc.)
Main-Class: mypackage.HelloWorld
Важливий момент! Після останнього рядка - в даному випадку ця вказівка Main - Class - має бути переклад рядка. Якщо його не буде - останній рядок не буде прочитаний. Швидше за все, це помилка в реалізації jar. Як би то не було - якщо в цьому прикладі ви не поставите у кінці переклад рядка, основний клас знайдений не буде і при запуску ви отримаєте помилку: 
Failed to load Main-Class manifest attribute from helloWorld.jar Отже, manifest.mf створили, переклад рядка не забули. Йдемо далі. Виконуємо команду по складанню архіву: jar cvmf manifest.mf helloWorld.jar -C ./classes mypackage  !!!Порядок ключів важливий. В якому порядку mі f - в такому ж порядку повинні бути імена manifest - і jar - файлів відповідно. manifest.mf- це ім'я файлу, в якому ми вказали виконуваний клас. В принципі,   цей файл може називатися як завгодно, як правило, ім'я таке (так цей файл називається у середині jar- архіву, і це ім'я вже фіксоване). helloWorld.jar - ім'я створюваного архіву. Конструкція "- C . /classes mypackage " означає змінити директорію на classes і узяти там директорію mypackage.  В результаті має бути створений файл helloWorld.jar з наступною структурою: META-INF/MANIFEST.MF mypackage/HelloWorld.class

Крок 6. Виконання програми запуском jar- файлу 
Виконуємо наступну команду: 
java -jar helloWorld.jar
Цю команду необов'язково виконувати з тієї директорії, де знаходиться корінь проекту. Можна вказати повний шлях, наприклад, так: 
java -jar c:\myprojects\HelloWorld\helloWorld.jar  Різниця тільки в тому, що поточною директорією додатка при запуску вважатиметься та, з якої ви запустили додаток на виконання. При використанні повного шляху вона може бути будь-якою, це іноді буває корисно.  В результаті виконання цієї команди, як і на кроці 4, в консоль буде виведений рядок "Hello, World"!

Ще один важливий момент! При запуску додатка через jar- файл, командою java - jar ..., у classpath потрапляє тільки цей jar- файл. Ніякі спроби вказати ключ – classpath ні до чого не приведуть. Проте не все так страшно, необхідні бібліотеки вказати можна. Для цього необхідно в маніфесті (manifest.mf) вказати відносні шляхи до бібліотек. Тобто, якщо нам потрібно підключити, наприклад, бібліотеки velocity - 1.4.jar і log4j - 1.2.8.jar, що лежать в директорії lib поряд з нашим jar- файлом, то в маніфест потрібно додати рядок: 
Manifest-Version: 1.0 
Created-By: 1.6.0_19 (Sun Microsystems Inc.)  Main-Class: mypackage.HelloWorld  Class-Path: lib/velocity-1.4.jar lib/log4j-1.2.8.jar 
Вказуються шляхи відносно jarфайлуроздільник - пропуск. І в цьому випадку в classpath буде включений не лише jar- файл, але і обидві вказані бібліотеки.

.