Вказівка інтерпретатору, де шукати класи
Інтерпретатору треба знати усі місця, де він може знайти класи. Що є таким місцем? Директорія і/або бібліотека -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- файл, але і обидві вказані бібліотеки.
Лабораторна робота
Пишемо програму 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- файл, але і обидві вказані бібліотеки.