Содержание | Предыдущая | Следующая
ГЛАВА 7
Программы на языке Ява организованы как наборы пакетов. Каждый пакет имеет собственный набор имен для типов, который помогает предотвращать конфликты между именами. Тип доступен
(§6.6) вне пакета, в котором он объявлен, только если этот тип объявлен как public.Структура наименования для пакетов является иерархической
(§7.1). Элементы пакета - это классовые и интерфейсные типы (§7.6), которые объявлены в модулях компиляции пакета, и подпакетах, которые могут содержать модули компиляции и их собственные подпакеты.Пакет можно сохранить в файловой системе
(§7.2.1) или в базе данных (§7.2.2). Пакеты, которые сохранены в файловой системе, имеют некоторые ограничения на организацию их модулей компиляции для более легкого нахождения классов. В любом случае, набор пакетов, доступных программе на Яве, определен базовой системой, но всегда должен включать по крайней мере три стандартных пакета java.lang, java.util, и java.io как определено в главах 20, 21, и 22. В большинстве вычислительных сред, стандартные пакеты java.applet, java.awt, и java.net, которые не описаны в этой спецификации, являются также доступными программам на Яве.Пакет состоит из ряда модулей компиляции
(§7.3). Модуль компиляции автоматически имеет доступ ко всем типам, объявленным в пакете и также автоматически импортирует каждый из типов, объявленных в предопределенном пакете java.lang.Модуль компиляции имеет три части, каждая из которых необязательная:
Для маленьких программ и случайной разработки, пакет может не иметь имени
(§7.4.2) или иметь простое имя, но если предполагается широкое использование кода Явы, желательно использовать уникальные имена пакетов (§7.7). Это может предотвратить конфликты, которые иначе бы произошли, если бы случилось так, что две группы выбрали одно и то же имя пакета, и эти пакеты позже использовались бы в одной и той же программе.Пакет может иметь члены любого или обоих из следующих видов:
Например, в стандартном Java Application Programming Interface:
Если
полностью квалифицированное имя (§6.7) пакета - P, а Q - подпакет P, то P.Q - это полностью квалифицированное имя подпакета.Подпакеты пакета
java: lang, util, и io (чьи полностью квалифицированные имена соответственно java.lang, java.util, и java.io) есть стандартная часть каждой реализации Явы и определены в Главах 20, 21, и 22. Многие реализации Явы будут включать полный набор пакетов Явы, определенный в сериях книг The Java Application Programming Interface.Пакет не может содержать объявление типа и подпакета с тем же самым именем, иначе возникнет ошибка времени компиляции. Вот некоторые примеры:
Иерархическая структура именования пакетов нужна для того, чтобы была удобной организация связанных пакетов стандартным способом, и запрещается, чтобы пакет имел подпакет с тем же самым простым именем, что и имя типа, объявленного в этом пакете. Не существует никакой специальной связи в языке Ява между пакетом, именованным
oliver и другим пакетом oliver.twist, или между пакетами, именованными evelyn.wood и evelyn.Waugh. Например, код в пакете, именованном oliver.twist не имеет лучшего доступа к типам, объявленным внутри пакета oliver, чем код в любом другом пакете.Каждая базовая система Явы определяет, в каком виде пакеты, модули компиляции, и подпакеты созданы и сохранены; какие имена верхнего уровня пакета находятся в области видимости в определенный момент компиляции; и какие пакеты доступны.
Пакеты могут хранится в локальной файловой системе в простых реализациях Явы. Другие реализации могут использовать распределенную файловую систему или некоторую форму базы данных, чтобы хранить исходные тексты программ на Яве и/или двоичный код.
Как чрезвычайно простой пример, все пакеты Явы (исходный текст и двоичный код) могут быть сохранены в одном каталоге и в его подкаталогах. Каждый непосредственный подкаталог этого каталога мог бы представлять пакет верхнего уровня, то есть тот, чье полностью квалифицированное имя состоит из одиночного простого имени. Каталог мог бы содержать следующие непосредственные подкаталоги:
COM gls jag java wnj
где каталог
java содержал бы пакеты стандартного Java Application Programming Interface, которые являются частью каждой стандартной системы; каталоги jag, gls, и wnj могли бы содержать пакеты, которые три автора этой спецификации создали для их персонального использования и совместного использования друг с другом внутри этой малой группы; и каталог COM содержал бы пакеты, заказываемые компаниями, использующими соглашения, описанные в §7.7, чтобы генерировать уникальные имена для их пакетов.В продолжении примера, каталог
java возможно содержал бы по крайней мере следующие подкаталоги:
applet awt io lang net util
cоответствующие стандартным пакетам
java.applet, java.awt, java.io, java.lang, java.net, и java.util, которые определены как часть стандартного Java Application Programming Interface.Продолжая пример, если бы мы заглянули внутрь каталога
util, мы бы увидели следующие файлы:BitSet.java Observable.java BitSet.class Observable.class Date.java Observer.java Date.class Observer.class Dictionary.java Properties.java Dictionary.class Properties.class EmptyStackException.java Random.java EmptyStackException.class Random.class Enumeration.java Stack.java Enumeration.class Stack.class Hashtable.java StringTokenizer.java Hashtable.class StringTokenizer.class NoSuchElementException.java Vector.java NoSuchElementException.class Vector.class
Где каждый из .
java файлов содержит исходный текст модуля компиляции (§7.3) который содержит определение класса или интерфейса, чья двоичная форма содержится в соответствующем файле с расширением .class.При этой простой организации пакетов, реализация Явы трансформировала бы имя пакета в путь, связывая компоненты имени пакета, размещая разделитель имени файла (индикатор каталога) между смежными компонентами. Например, если эта простая организация использовалась на системе U
NIX, где разделитель имен файла есть /, имя пакетаjag.scrabble.board
было бы преобразовано в имя каталога
jag/scrabble/board
и:
COM.Sun.sunsoft.DOE
было бы преобразовано в имя каталога
COM/Sun/sunsoft/DOE
Фактически, стандартный JavaSoft Java Developer's Kit на UNIX отличается от самой простой дисциплины, описанной здесь только тем, что он имеет системную переменную
CLASSPATH, которая определяет набор каталогов, каждый из которых обрабатывается подобно одиночному каталогу, описанному здесь. Эти каталоги ищут для определения именованных пакетов и типов.Компонент имени пакета или имени класса может содержать символ, который не может появляться в имени обычного каталога файловой системы, такой как символ Unicode на системе, которая допускает использование только символов ASCII в именах файла. По стандарту, символ может быть использован, при использовании символа @ после которого идут четыре шестнадцатеричные цифры, дающие числовое значение символа, как в последовательности \
uxxxx (§3.3), таким образом имя пакета:children.activities.crafts.papierM\u00e2ch\u00e9
которое может быть также записано, используя Unicode как:
children.activities.crafts.papierMache
может быть преобразовано в имя каталога
children/activities/crafts/papierM@00e2ch@00e9
Если символ
@ – недопустимый символ в имени файла для данной файловой системы, то какой-то другой символ, который не допустим в Яве, может использоваться вместо него.Базовая система может хранить пакеты и их модули компиляции и подпакеты в базе данных.
Ява разрешает, чтобы такая база данных ослабила ограничения
(§7.6) на модули компиляции в реализациях с файловой основой. Например, при использовании базы данных для хранения пакетов, нет ограничения на число классов или интерфейсов, объявленных с модификатором public, в каждом модуле компиляции. Системы, которые используют базу данных, должны, однако, обеспечить опцию, чтобы преобразовать программу на Яве в форму, которая удовлетворяет условиям ограничений, для целей экспорта реализации с файловой основой.Модуль компиляции - это начальный символ
(§2.1) для синтаксической грамматики (§2.3) программ на Яве. Он определен, используя следующие продукции:CompilationUnit: PackageDeclarationoptImportDeclarationsopt
TypeDeclarationsopt ImportDeclarations: ImportDeclaration ImportDeclarations
ImportDeclaration TypeDeclarations: TypeDeclaration TypeDeclarations
TypeDeclaration
Типы, объявленные в различных модулях компиляции могут зависеть друг от друга. Компилятор языка Ява должен упорядочивать типы, чтобы компилировать их в одно и то же время.
Модуль компиляции состоит из трех частей, каждая из которых необязательная:
Каждый модуль компиляции автоматически и неявно импортирует всякое имя типа с модификатором
public, объявленное в предопределенном пакете java.lang, так, чтобы имена всех типов были доступны как простые имена, как описано в §7.5.3.Объявление пакета появляется внутри модуля компиляции, чтобы указать пакет, которому данный модуль принадлежит. Модуль компиляции, который не содержит никакого объявления пакета есть часть неименованного пакета.
Объявление пакета в модуле компиляции определяет имя
(§6.2) пакета, которому модуль компиляции принадлежит.PackageDeclaration:package
PackageName;
Имя пакета, упомянутое в объявлении пакета должно быть полностью квалифицированным именем (§6.7) пакета.
Если тип T объявлен в модуле компиляции пакета, чье полностью квалифицированное имя есть P, то полностью квалифицированное имя типа есть P.T; таким образом в примере:
package wnj.points; class Point { int x, y; }
полностью квалифицированное имя класса Point есть wnj.points.Point.
Модуль компиляции, который не содержит никакого объявления пакета есть часть неименованного пакета. Например, модуль компиляции:
class FirstCall { public static void main(String[] args) { System.out.println("Mr. Watson, come here. " + "I want you."); } }
определяет очень простой модуль компиляции как часть неименованного пакета.
Система Явы должна поддерживать по крайней мере один неименованный пакет; но она может поддерживать и более одного, но этого не требуется. Какие модули компиляции находятся в каждом неименованном пакете определяется базовой системой.
В системах, которые используют иерархическую файловую систему для хранения пакетов, основной задачей является связать неименованный пакет с каждым каталогом; только один неименованный пакет доступен в данный момент, а именно тот, который связан с "текущим рабочим каталогом". Точное значение "текущего рабочего каталога" зависит от базовой системы.
Неименованные пакеты обеспечиваются Явой главным образом для удобства при разработке маленьких или временных прикладных программ или при начальной стадии разработки.
При использовании неименованных пакетов должны быть приняты меры предосторожности. Модуль компиляции в именованном пакете может импортировать тип из неименованного пакета, но тогда компилируемая версия этого модуля компиляции будет правильно затем работать только, когда тот неименованный пакет является "текущим". По этой причине, настоятельно рекомендуется, чтобы модули компиляции именованных пакетов никогда не импортировали типы из неименованных пакетов. Также рекомендуется, чтобы любой тип, объявленный в неименованном пакете, не был объявлен с модификатором public, чтобы предохранить его от случайного импорта именованным пакетом.
Рекомендуется, чтобы базовая система гарантировала, что не будет последствий в ситуациях, где модули компиляции именованных пакетов импортируют типы из неименованных пакетов. Одним из способов является связать с каждым именованным пакетом самое большее один неименованный пакет, и затем обнаруживать и предупреждать о ситуациях, в которых именованный пакет используется больше чем одним неименованным пакетом. Это специально не требуется, но это необходимо для реализаций, чтобы поддерживать использование именованного пакета более чем одним неименованным пакетом, сохраняя многократно компилируемые версии именованного пакета.
Какие имена пакета верхнего уровня находятся в области действия, (
§6.3, §6.5)определяется в соответствии с соглашениями базовой системы.Имена пакетов никогда не скрывают другие имена.
Базовая система определяет, разрешен ли доступ к членам пакета. Пакет
java должен всегда быть доступен вместе с его стандартными подпакетами lang, io, и util .Настоятельно рекомендуется, чтобы защита файловой системы или базы данных, используемых для сохранения программ на Яве, была установлена так, чтобы все модули компиляции пакета были доступны.
Объявление импорта (import) разрешает использовать простые имена, объявленные в другом пакете
(§6.2), состоящие из одиночного идентификатора. Без использования соответствующего объявления import, единственный способ обратиться к типу, объявленному в другом пакете состоит в том, чтобы использовать полностью квалифицированное имя (§6.7).ImportDeclaration: SingleTypeImportDeclaration TypeImportOnDemandDeclaration
объявление одиночного импорта типа (§7.5.1) импортирует одиночный тип, упоминая полностью квалифицированное имя. Объявление импорта типа по шаблону(§7.5.2) импортирует все типы именованного пакета, объявленные public.
Объявление
import делает типы доступными по их простым именам только внутри модуля компиляции, который содержит объявление import. Область действия имени (имен) не включает в себя оператор package, другие import-операторы текущего модуля компиляции, или другие модули компиляции в том же пакете. Пожалуйста для пояснения смотрите пример из. §7.5.4.7.5.1 Объявление одиночного импорта типа
Объявление одиночного импорта типа импортирует простой тип, давая полностью квалифицированное имя и делая его доступным под простым именем в объявлениях класса и интерфейса в модуле компиляции.
SingleTypeImportDeclaration:import
TypeName;
TypeName должно быть полностью квалифицированным именем классового или интерфейсного типа; если такой тип не существует, то происходит ошибка времени компиляции. Если данного типа нет в текущем пакете, то он должен быть доступным (§6.6); для этого он должен быть объявлен public (§8.1.2, §9.1.2), иначе происходит ошибка времени компиляции.
Пример:
import java.util.Vector;делает простое имя
Vector доступным внутри объявлений классов и интерфейсов в модуле компиляции. Таким образом, простое имя Vector ссылается на тип Vector в пакете java.util во всех местах, где оно не скрыто (§6.3) объявлением поля, параметра, или локальной переменной с тем же самым именем.Если два
import-объявления простого типа в том же самом модуле компиляции пытаются импортировать типы с одним и тем же простым именем, то происходит ошибка времени компиляции, за исключением случая, если два типа являются одним и тем же типом, тогда повторное объявление игнорируется. Если другой тип с тем же самым именем иначе объявлен в текущем модуле компиляции, за исключением объявления импорта типа по шаблону (§7.5.2), то происходит ошибка времени компиляции.Так в программе:
import java.util.Vector; class Vector { Object[] vec; }
возникает ошибка времени компиляции из-за двойного объявления Vector, также как :
import java.util.Vector; import myVector.Vector;
где myVector - пакет, содержащий модуль компиляции:
package myVector; public class Vector { Object[] vec; }
Компилятор следит за типами по их полностью квалифицированным именам (§6.7). Простые имена и cоставные имена могут использоваться равнозначно всякий раз, когда они оба доступны.
Обратите внимание, что импорт не может импортировать подпакет, только тип. Например, ничего не выйдет, если пробовать импортировать java.util и затем использовать имя util.Random, чтобы обратиться к типу java.util.Random:
import java.util; // неправильно: ошибка времени компиляции class Test { util.Random generator; }
Объявление импорта типа по шаблону позволяет всем
public типам, объявленным в пакете, имеющем полностью квалифицированное имя, быть импортируемыми, если это необходимо.TypeImportOnDemandDeclaration:import
PackageName. * ;
Если назвать пакет, который не доступен (§6.6), как определено Ява-системой (§7.2), то это ошибка времени компиляции для объявление импорта типа по шаблону. Два или больше объявления импорта типа по шаблону в одном и том же модуле компиляции могут использовать тот же самый пакет; это то же самое, как если бы имелось ровно одно такое объявление. Ошибки времени компиляции не возникает, если указать имя текущего пакета или java.lang в объявлении импорта типа по шаблону, даже если они уже импортируются; дубликат объявления импорта типа по шаблону игнорируется.
Пример:
import java.util. *;делает простые имена всех
public-типов, объявленных в пакете java.util доступными внутри класса и интерфейса в модуле компиляции. Таким образом, простое имя Vector относится к типу Vector в пакете java.util во всех местах, где оно не скрыто (§6.3) import-объявлением простого типа, чье простое имя есть Vector; типом, именованным Vector и объявленным в пакете, которому принадлежит модуль компиляции; или объявлением поля, параметра, или локальной переменной, имеющими имя Vector. (Это было бы необычно, если бы какое-нибудь из этих условий произошло.)Каждый модуль компиляции автоматически импортирует каждое имя
public-типа, объявленное в предопределенном пакете java.lang, как будто в начале каждого модуля компиляции помещено объявление: import java.lang. *;сразу же после заголовка пакета
Полная спецификация
java.lang дана в главе 20. В java.lang определены следующие public- типы:AbstractMethodError LinkageError ArithmeticException Long ArrayStoreException Math Boolean NegativeArraySizeException Character NoClassDefFoundError Class NoSuchFieldError ClassCastException NoSuchMethodError ClassCircularityError NullPointerException ClassFormatError Number ClassLoader NumberFormatException ClassNotFoundException Object CloneNotSupportedException OutOfMemoryError Cloneable Process Compiler Runnable Double Runtime Error RuntimeException Exception SecurityException ExceptionInInitializerError SecurityManager Float StackOverflowError IllegalAccessError String IllegalAccessException StringBuffer IllegalArgumentException System IllegalMonitorStateException Thread IllegalThreadStateException ThreadDeath IncompatibleClassChangeError ThreadGroup IndexOutOfBoundsException Throwable InstantiationError UnknownError InstantiationException UnsatisfiedLinkError Integer VerifyError InternalError VirtualMachineError InterruptedException
Имена пакетов и имена типов обычно различны по соглашениям, описанным в
§6.8. Однако, в придуманном примере, где имеется нетрадиционно именованный пакет Vector, который объявляетpublic
класс,
именованный Mosquito:
package Vector; public class Mosquito { int capacity; }
и затем модуль компиляции:
package strange.example; import java.util.Vector; import Vector.Mosquito;
class Test { public static void main(String[] args) { System.out.println(new Vector().getClass()); System.out.println(new Mosquito().getClass()); } }
import-объявление простого типа (§7.5.1), импортирующее класс Vector из пакета java.util, допускает, чтобы имя пакета Vector от появления и правильного распознавания в последующих объявлениях импорта. Пример выводит:
class java.util.Vectorclass Vector.Mosquito
Объявление типа объявляет классовый
(§8) или интерфейсный (§9) типы:
TypeDeclaration:
ClassDeclaration
InterfaceDeclaration
;
Компилятор Явы должен игнорировать дополнительные ";" лексемы, появляющиеся на уровне объявлений типа. Лишние точки с запятой разрешаются в Яве исключительно как уступка программистам на C++, которые используют для записи:
class date { int month, day, year; };
( В C++, но не в Яве, любой может использовать отделенный запятой список идентификаторов, чтобы объявить переменные между "}" и ";".). Дополнительные точки с запятой не должны использоваться в новом коде Явы. Программное обеспечение, которое переформатирует код Явы, может удалить их.
По умолчанию, типы, объявленные в пакете доступны только внутри модулей компиляции этого пакета, но тип может быть объявлен public, чтобы предоставить доступ к типу из кода в других пакетах (§6.6, §8.1.2, §9.1.2).
Реализация Явы должна следить за типами внутри пакетов по их полностью квалифицированным именам
(§6.7). Различные способы именования типа должны быть расширены до полностью квалифицированных имен, чтобы удостовериться, что такие имена распознаны как ссылка на тот же самый тип. Например, если модуль компиляции содержит import-объявление простого типа (§7.5.1):import java.util.Vector;
то внутри этого модуля компиляции простое имя Vector и полностью квалифицированное имя java.util.Vector одного и того же типа.
Когда пакеты Явы хранятся в файловой системе (§7.2.1), то происходит ошибка времени компиляции, если тип не найден в файле под именем, составленным из имени типа плюс расширение ( .java или .jav), если любое из следующих утверждений истинно:
Это ограничение подразумевает, что должен быть по крайней мере один такой тип на каждый модуль компиляции. Это ограничение делает более легким для компилятора Явы и виртуальной машины Явы нахождение именованного класса внутри пакета; например, исходный код для public типа wet.sprocket.Toad должен находиться в файле Toad.java в каталоге wet/ sprocket, и соответствующий объектный код будет найден в файле Toad.class в том же самом каталоге.
Если пакеты Явы хранятся в базе данных (§7.2.2), то система Явы не обязана накладывать такие ограничения.
Практически, многие программисты на Яве предпочитают размещать каждый классовый или интерфейсный тип в его собственный модуль компиляции, несмотря на то, является ли он общим или на него ссылаются при помощи кода в других модулях компиляции.
Разработчики должны что-то предпринять, чтобы избежать возможности для двух пакетов иметь одно имя, выбирая уникальные имена пакета для пакетов. Это позволяет пакетам быть легко и автоматически устанавливаемыми и каталогизируемыми. Этот раздел определяет стандартное соглашение, не предписанное компилятором Явы, для создания таких уникальных имен пакета. Система Явы стремится обеспечить автоматическое преобразование локальных и случайных имен пакета в уникальные имена, описанные здесь.
Если уникальные имена пакетов не используются, то конфликты имен пакетов могут возникать далеко от места создания любого из находящихся в противоречии пакетов. Это может создать неразрешимую ситуацию для пользователя или программиста. Класс
ClassLoader (§20.14) из стандартного окружения виртуальной машины Явы может быть использован, чтобы изолировать пакеты с одним и тем же именем друг от друга в тех случаях, где пакеты вынуждены взаимодействовать, но не совсем понятным способом.Когда вы создаете уникальное имя пакета, то сначала вы пишите имя домена в Internet, которому вы принадлежите (или имя организации, которая имеет к нему принадлежит ), например,
Sun.COM. Затем вы переставляете компонент за компонентом, чтобы получить в этом примере COM.Sun, и используете его как префикс для ваших имен пакета, используя соглашение, разработанное внутри вашей организации.Такое соглашение могло бы определять, что некоторый компонент имени каталога может означать отделение, проект, машину, или имя входа в систему. Некоторые примеры:
COM.Sun.sunsoft.DOE COM.Sun.java.jag.scrabble COM.Apple.quicktime.v2 EDU.cmu.cs.bovik.cheese GOV.whitehouse.socks.mousefinder
Первый компонент уникального имени пакета всегда пишется заглавными буквами ASCII и должен быть одним из имен верхнего уровня, в настоящее время COM, EDU, GOV, МIL, NET, ORG, или одного из двухбуквенных английских кодов, идентифицирующих страны как определено в
ISO Standard 3166, 1981. Для подробной информации, обратитесь к документам, хранящимся в ftp://rs.internic.net/rfc, например, rfc920.txt и rfc1032.txt.Имя пакета не обязательно означает, где пакет сохранен в Internet; например, пакет, именованный
EDU.cmu.cs.bovik.cheese не обязательно доступен из адреса Internet cmu.EDU или из cs.cmu.EDU или из bovik.cs.cmu.EDU. Соглашение в Яве для создания уникальных имен пакета - просто способ добавления к существующему, широко известного уникального имени вместо того, чтобы создавать отдельную регистрацию для имени пакета в Яве.Если вам нужно получить новое имя домена в Internet, вы можете взять анкету из
ftp://ftp.internic.net и отправить предложенные полные формы по электронной почте в domreg@internic.net. Чтобы выяснять, каковы в настоящее время зарегистрированные имена областей, вы можете подсоединиться к rs.internic.net и использовать средство whois.