import java.util *,
Механизм импортирования обеспечивает возможность управления пространствами имен. Имена членов классов изолируются друг от друга. Метод f() класса А не конфликтует с методом f() с таким же определением (списком аргументов) класса В. А как насчет имен классов? Предположим, что класс Stack создается на компьютере, где кем-то другим уже был определен класс с именем Stack. Потенциальные конфликты имен — основная причина, по которой так важны управление пространствами имен в Java и возможность создания уникальных идентификаторов для всех классов.
До этого момента большинство примеров книги записывались в отдельных файлах и предназначались для локального использования, поэтому на имена пакетов можно было не обращать внимания. (В таком случае имена классов размещаются в «пакете по умолчанию».) Конечно, это тоже решение, и такой подход будет применяться в книге, где только возможно. Но, если вы создаете библиотеку или программу, использующую другие программы Java на этой же машине, стоит подумать о предотвращении конфликтов имен.
Файл с исходным текстом на Java часто называют компилируемым модулем. Имя каждого компилируемого модуля должно завершаться суффиксом .java, а внутри него может находиться открытый (public) класс, имеющий то же имя, что и файл (с заглавной буквы, но без расширения .java). Любой компилируемый модуль может содержать не более одного открытого класса, иначе компилятор сообщит об ошибке. Остальные классы модуля, если они там есть, скрыты от окружающего мира — они не являются открытыми (public) и считаются «вспомогательными» по отношению к главному открытому классу.
В результате компиляции для каждого класса, определенного в файле .java, создается класс с тем же именемГно с расширением .class. Таким образом, при компиляции нескольких файлов .java может появиться целый ряд файлов с расширением .class. Если вы программировали на компилируемом языке, то, наверное, привыкли к тому, что компилятор генерирует промежуточные файлы (обычно с расширением OBJ), которые затем объединяются компоновщиком для получения исполняемого файла или библиотеки. Java работает не так. Рабочая программа представляет собой набор однородных файлов .class, которые объединяются в пакет и сжимаются в файл JAR (утилитой Java jar). Интерпретатор Java отвечает за поиск, загрузку и интерпретацию[1] этих файлов.
Библиотека также является набором файлов с классами. В каждом файле имеется один public-класс с любым количеством классов, не имеющих спецификатора public. Если вы хотите объявить, что все эти компоненты (хранящиеся в отдельных файлах .java и .class) связаны друг с другом, воспользуйтесь ключевым словом package.
Директива package должна находиться в первой незакомментированной строке файла. Так, команда.
package access;
означает, что данный компилируемый модуль входит в библиотеку с именем access. Иначе говоря, вы указываете, что открытый класс в этом компилируемом модуле принадлежит имени mypackage и, если кто-то захочет использовать его, ему придется полностью записать или имя класса, или директиву import с access (конструкция, указанная выше). Заметьте, что по правилам Java имена пакетов записываются только строчными буквами.
Предположим, файл называется MyClass.java. Он может содержать один и только один открытый класс (public), причем последний должен называться MyClass (с учетом регистра символов):
//: access/mypackage/MyClass java
package access.mypackage;
public class MyClass { 11 ...
} ///.-
Если теперь кто-то захочет использовать MyClass или любые другие открытые классы из пакета access, ему придется использовать ключевое слово import, чтобы имена из access стали доступными. Возможен и другой вариант — записать полное имя класса:
//: access/QualifiedMyClass java
public class QualifiedMyClass {
public static void main(String[] args) { access mypackage.MyClass m =
new access mypackage.MyClass();
}
} ///:-
С ключевым словом import решение выглядит гораздо аккуратнее:
II: access/ImportedMyClass.java
import access.mypackage.*:
public class ImportedMyClass {
public static void main(String[] args) { MyClass m = new MyClassO:
}
} ///
Ключевые слова package и import позволяют разработчику библиотеки организовать логическое деление глобального пространства имен, предотвращающее конфликты имен независимо от того, сколько людей подключится к Интернету и начнет писать свои классы на Java.
Создание уникальных имен пакетов
Вы можете заметить, что, поскольку пакет на самом деле никогда не «упаковывается» в единый файл, он может состоять из множества файлов .class, что способно привести к беспорядку, может, даже хаосу. Для предотвращения проблемы логично было бы разместить все файлы .class конкретного пакета в одном каталоге, то есть воспользоваться иерархической структурой файловой системы. Это первый способ решения проблемы нагромождения файлов в Java; о втором вы узнаете при описании утилиты jar.
Размещение файлов пакета в отдельном каталоге решает две другие задачи: создание уникальных имен пакетов и обнаружение классов, потерянных в «дебрях» структуры каталогов. Как было упомянуто в главе 2, проблема решается «кодированием» пути файла в имени пакета. По общепринятой схеме первая часть имени пакета должна состоять из перевернутого доменного имени разработчика класса. Так как доменные имена Интернета уникальны, соблюдение этого правила обеспечит уникальность имен пакетов и предотвратит конфликты. (Только если ваше доменное имя не достанется кому-то другому, кто начнет писать программы на Java под тем же именем.) Конечно, если у вас нет собственного доменного имени, для создания уникальных имен пакетов придется придумать комбинацию с малой вероятностью повторения (скажем, имя и фамилия). Если же вы решите публиковать свои программы на Java, стоит немного потратиться на получение собственного доменного имени.
Вторая составляющая — преобразование имени пакета в каталог на диске компьютера. Если программе во время исполнения понадобится загрузить файл .class (что делается динамически, в точке, где программа создает объект определенного класса, или при запросе доступа к статическим членам класса), она может найти каталог, в котором располагается файл .class.
Интерпретатор Java действует по следующей схеме. Сначала он проверяет переменную окружения CLASSPATH (ее значение задается операционной системой, а иногда программой установки Java или инструментарием Java). CLASSPATH содержит список из одного или нескольких каталогов, используемых в качестве корневых при поиске файлов .class. Начиная с этих корневых каталогов, интерпретатор берет имя пакета и заменяет точки на слеши для получения полного пути (таким образом, директива package foo.bar.baz преобразуется в foo\bar\baz, foo/bar/baz или что-то еще в зависимости от вашей операционной системы). Затем полученное имя присоединяется к различным элементам CLASSPATH. В указанных местах ведется поиск файлов .class, имена которых совпадают с именем создаваемого программой класса. (Поиск также ведется в стандартных каталогах, определяемых местонахождением интерпретатора Java.)
Чтобы понять все сказанное, рассмотрим мое доменное имя: MindView.net. Обращая его, получаем уникальное глобальное имя для моих классов: net. mindview. (Расширения com, edu, org и другие в пакетах Java прежде записывались в верхнем регистре, но начиная с версии Java 2 имена пакетов записываются только строчными буквами.) Если потребуется создать библиотеку с именем simple, я получаю следующее имя пакета:
package net.mindview.simple,
Теперь полученное имя пакета можно использовать в качестве объединяющего пространства имен для следующих двух файлов:
//: net/mindview/simple/Vector.java
// Создание пакета