Шаг 51.
Язык программирования Java.
Jar-файлы. Общие сведения

На этом шаге мы поговорим про Jar-файлы

Приложение обычно упаковывается для того, чтобы предоставить в распоряжение пользователя единственный файл, а не целую структуру каталогов, заполненную файлами классов. Специально для этой цели был разработан формат архивный файлов Java Archive (здесь и далее JAR-файл). Файл формата JAR может содержать, помимо файлов классов, файлы других типов, в том числе файлы изображений и звуковые файлы. Более того, JAR-файлы уплотняются по широко известному алгоритму сжатия данных в формате ZIP.

Для создания JAR-файлов служит утилита jar. Новый JAR-файл создается с помощью следующего синтаксиса командной строки:

jar параметры файл_1 файл_2 ...

Например:

jar cvf CalculatorClasses.jar *.java icon.gif

В таблице 1 перечислены все параметры утилиты jar.

Таблица 1. Параметры утилиты jar
Параметр Описание
c Создает новый или пустой архив и добавляет в него файлы. Если в качестве имени файла указано имя каталога, утилита jar обрабатывает его рекурсивно
C Временно изменяет каталог. Например, следующая команда направляет файлы в подкаталог classes:
jar cvf JARFileName.jar -C classes *.class
e Создает точку входа в манифест
f Задает имя JAR-файла в качестве второго параметра командной строки. Если этот параметр пропущен, то утилита jar выводит результат в стандартный поток вывода (при создании JAR-файла) или вводит его из стандартного потока ввода (при извлечении или просмотре содержимого JAR-файла)
i Создает индексный файл (для ускорения поиска в крупных архивах)
m Добавляет в JAR-файл манифест, представляющий собой описание содержимого архива и его происхождения. Манифест создается по умолчанию каждого архива, но для подробного описание содержимого JAR-файла можно создать свой собственный манифест
M Отменяет создание манифеста
t Отображает содержание архива
u Обновляет существующий JAR-файл
v Выводит подробные сведения об архиве
x Извлекает файлы. Если указано несколько имен файлов, извлекаются только они. В противном случае извлекаются все файлы
o Сохраняет данные в архиве, не упаковывая их в формате ZIP

Помимо файлов классов, изображений и прочих ресурсов, каждый JAR-файл содержит также файл манифеста, описывающий особые характеристики данного архива. Файл манифеста называется MANIFEST.MF и находится в специальном подкаталоге META-INF. Ниже приведен минимально допустимый манифест:

Manifest-Version: 1.0

Сложные манифесты содержат много больше элементов описания, группируемых по разделам. Первый раздел манифеста называется главным. Он относится ко всему JAR-файлу. Остальные элементы описания относятся к отдельным файлам, пакетам или URL. Эти элементы должны начинаться со слова Name. Разделы отделяются друг от друга пустыми строками. Приведем ниже пример манифеста.

Manifest-Version: 1.0
строки описания данного архива

Name: Woozle.class
строки описания данного файла

Name: com/mycompany/mypkg/
строки описания данного пакета

Заметим, что последняя строка в манифесте должна оканчиваться символом перевода строки. В противном случае манифест не будет прочитан правильно.

Для того чтобы отредактировать этот манифест, достаточно ввести в него нужные строки, сохранив их в обычном текстовом файле, а затем выполнить следующую команду:

jar cfm имяJAR-файла имяФайлаМанифеста

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

jar cfm MyArchive.jar manifest.mf com/mycompany/mypkg/*.class

Чтобы добавить манифест в существующий JAR-файл, достаточно выполнить следующую команду:

jar ufm MyArchive.jar manifest.mf

С помощью параметра e утилиты jar можно указывать точку входа в прикладную программу, то есть класс, который будет обычно указываться при запуске программы по команде java.

jar cvfe MyProgram.jar com.mycompany.mypkg.MainAppClass добавляемые файлы

Также, в манифесте можно указать главный класс прикладной программы, включая оператор в следующей форме:

Main-Class: com.mycompany.mypkg.MainAppClass

Заметим, что не нужно добавлять расширение .class к имени главного класса. Независимо от способа указания точки входа в прикладную программу ее пользователи могут запустить ее на выполнение, введя следующую команду:

java -jar MyProgram.jar

В зависимости от конфигурации операционной системы приложения можно запускать двойным щелчком на пиктограмме JAR-файла. Приведем ниже особенности запуска приложений из JAR-файлов в разных операционных системах:

Но программа на Java, находящаяся в JAR-файле, имеет тот же вид, что и собственное приложение операционной системы. В Windows можно использовать утилиты-оболочки сторонних производителей, превращающие JAR-файлы в исполняемые файлы Windows. Такая оболочка представляет собой программу для Windows с расширением .exe, которая запускает виртуальную машину Java (JVM) или же сообщает пользователю, что делать, если эта машина не найдена.

На платформе Mac OS дело обстоит немного проще. Утилита Jar Bundler, входящая в состав ИСР XCode, позволяет превратить JAR-файл в первоклассное приложение для Mac OS.

Классы, применяемые в аплетах и приложениях, часто ассоциируются с файлами данных. Это могут быть:

В Java все эти файлы называются ресурсами.

Предположим, что вы написали программу для учета книг в вашей домашней библиотеки. Вы решили купить новое издание уже имеющейся у вас книги. Безусловно, название описание и год выпуска книги изменятся. Для того чтобы легко отслеживать такие изменения, текст описания книги следует разместить в отдельном файле, а не встраивать его в программу в виде символьной строки. Разумеется, этот файл нужно разместить вместе с остальными файлами программы, например в JAR-файле.

Загрузчику классов известно, где находятся файлы классов, если они содержатся в каталогах, указанных в переменной окружения CLASSPATH, в архиве или на веб-сервере. Механизм ресурсов представляет аналогичные удобства и при обращении с файлами, которые не являются файлами классов. Для этого необходимо выполнить описанные ниже действия:

  1. Получить объект типа Class, имеющий ресурс, например AboutPanel.class.
  2. Если ресурс представляет собой графический или звуковой файл, вызвать метод getResource(имя файла), чтобы определить местонахождения ресурса в виде URL. Затем прочитать его непосредственно с помощью метода getImage() или getAudioClip().
  3. Если ресурс не является графическим или звуковым файлом, вызвать метод getResourceAsStream(), чтобы прочитать данные из файла.

Загрузчик помнит, где располагается класс, и может обнаружить там же файлы ресурсов. Приведем ниже пример:

URL url = ResourceTest.class.getResource("about.gif");
Image img = new ImageIcon(url).getImage();

InputStream stream = ResourceTest.class.getResourceAsStream("about.txt");
Scanner in = new Scanner(stream);

Ресурсы совсем не обязательно размещать в одном каталоге с файлом классов. Можно задавать относительные пути:

data/text/about.txt

Это относительное имя ресурса, поэтому оно определяется относительно пакета, которому принадлежит класс, загружающий этот ресурс. Обратим внимание на то, что в этом имени всегда нужно использовать разделитель /, независимо от тех разделителей, которые применяются в операционной системе. Например, на платформе Windows загрузчик ресурсов автоматически преобразует символ / в разделитель \.

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

Кроме того, ресурсы применяются для интернационализации программ. В файлах ресурсов, например, содержатся сообщения и метки на разных языках. Каждый такой файл соответствует отдельному языку. В прикладном интерфейсе API (его мы рассмотрим позднее) для интернационализации поддерживается стандартный способ организации и доступа к этим файлам локализации.

Пакет, написанный на Java, можно герметизировать, чтобы в него больше нельзя было добавлять новые классы. Разработчики обычно применяют герметизацию в том случае, если они используют классы, методы и поля, имеющие область действия, ограниченную пакетом.

Так, если герметизируется пакет com.mycompany.util, то ни один из классов, находящихся за пределами герметизированного архива, нельзя будет определить с помощью следующего оператора:

package com.mycompany.util;

Для этого все классы из пакета размещаются в JAR-файле. По умолчанию пакеты в JAR-файле не герметизированы. Изменить глобальные установки по умолчанию можно, введя в главный раздел файла манифеста следующую строку:

Sealed: true

Для каждого пакета можно отдельно указать, следует ли его герметизировать, добавив в файл манифеста новый раздел, как показано ниже:

Name: com/mycompany/util
Sealed: true

Name: com/mycompany/misc
Sealed: false

Для того чтобы герметизировать пакет, необходимо выполнить следующую команду:

jar cvfm MyArchive.jar manifest.mf добавляемые файлы

На следующем шаге мы начнем говорить про обработку ошибок

Предыдущий шаг Содержание Следующий шаг