Spec-Zone.ru › Java Language Specification 11

Глава 7. Пакеты и модули

Оглавление

7.1. Члены пакета
7.2. Поддержка хоста для модулей и пакетов
7.3. Единицы компиляции
7.4. Объявления пакетов
7.4.1. Имянные пакеты
7.4.2. Без имени пакеты
7.4.3. Наблюдаемость и видимость пакета
7.5. Объявления импорта
7.5.1. Объявления импорта одного типа
7.5.2. Объявления импорта типа по умолчанию
7.5.3. Объявления импорта одного статического элемента
7.5.4. Объявления импорта статического элемента по умолчанию
7.6. Объявления типов верхнего уровня
7.7. Объявления модулей
7.7.1. Зависимости
7.7.2. Экспортируемые и открытые пакеты
7.7.3. Потребление сервисов
7.7.4. Предоставление сервисов
7.7.5. Модули без имени
7.7.6. Наблюдаемость модуля

Программы организованы как наборы пакетов. Члены пакета (§7.1) — это классы и интерфейсы, которые объявляются в единицах компиляции пакета, а также подпакеты, которые могут содержать свои единицы компиляции и подпакеты.

Каждый пакет имеет свой собственный набор имён для типов, что помогает предотвратить конфликты имён. Структура именования пакетов иерархическая.

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

Модули и пакеты могут храниться в файловой системе или в базе данных (§7.2). Модули и пакеты, которые хранятся в файловой системе, могут иметь определённые ограничения на организацию своих единиц компиляции, чтобы позволить простой реализации легко находить объявления модулей и типов.

Код в единице компиляции автоматически получает доступ ко всем типам, объявленным в его пакете, и также автоматически импортирует все public типы, объявленные в предопределённом пакете java.lang.

Тип верхнего уровня доступен (§6.6) вне пакета, который его объявляет, только если тип объявлен public. Тип верхнего уровня доступен вне модуля, который его объявляет, только если тип объявлен public и является членом экспортируемого пакета. Тип, который объявлен public, но не является членом экспортируемого пакета, доступен только коду внутри модуля.

Для небольших программ и несложной разработки пакет может быть безымянным (§7.4.2) или иметь простое имя, но если код будет широко распространяться, следует выбирать уникальные имена пакетов с использованием квалифицированных имён. Это предотвращает конфликты, которые могут возникнуть, если две группы разработчиков случайно выберут одно и то же имя пакета, а эти пакеты позже будут использоваться в одной программе.

7.1. Члены пакета

Членами пакета являются его подпакеты и все типы классов верхнего уровня (§7.6, §8 (Классы)) и типы интерфейсов верхнего уровня (§9 (Интерфейсы)), объявленные во всех единицах компиляции (§7.3) пакета.

Например, в API платформы Java SE:

  • Пакет java имеет подпакеты awt, applet, io, lang, net и util, но не содержит единиц компиляции.

  • Пакет java.awt имеет подпакет с именем image, а также ряд единиц компиляции, содержащих объявления типов классов и интерфейсов.

Если полное имя (§6.7) пакета — это P, и Q — подпакет P, то P.Q — полное имя подпакета и обозначает пакет.

В одном пакете не может быть двух членов с одинаковым именем, в противном случае возникает ошибка времени компиляции.

Вот несколько примеров:

  • Поскольку пакет java.awt содержит подпакет image, он не может (и не содержит) объявления класса или типа интерфейса с именем image.

  • Если есть пакет с именем mouse и тип-член Button в этом пакете (который затем можно обозначить как mouse.Button), то не может быть пакета с полным именем mouse.Button или mouse.Button.Click.

  • Если com.nighthacks.java.jag — полное имя типа, то не может быть пакета с полным именем либо com.nighthacks.java.jag, либо com.nighthacks.java.jag.scrabble.

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


package vector;
public class Vector { Object[] vec; }

который содержит класс public с именем Vector, даже если пакет java.util также объявляет класс с именем Vector. Эти два типа классов различны, что отражается в их разных полных именах (§6.7). Полное имя этого примера Vector — vector.Vector, тогда как java.util.Vector — полное имя класса Vector, включённого в платформу Java SE. Поскольку пакет vector содержит класс с именем Vector, он не может также содержать подпакет с именем Vector.

Иерархическая структура имён пакетов предназначена для удобной организации связанных пакетов стандартным способом, но сама по себе не имеет никакого значения, кроме запрета наличия в пакете подпакета с тем же простым именем, что и тип верхнего уровня (§7.6) объявленный в этом пакете.

Например, нет особых отношений доступа между пакетом с именем oliver и другим пакетом с именем oliver.twist, или между пакетами с именами evelyn.wood и evelyn.waugh. То есть, код в пакете с именем oliver.twist не имеет лучшего доступа к типам, объявленным в пакете oliver, чем код в любом другом пакете.

7.2. Поддержка модулей и пакетов хост-системой

Каждая хост-система определяет, как создаются и хранятся модули, пакеты и единицы компиляции.

Каждая хост-система определяет, какие единицы компиляции являются наблюдаемыми в конкретной компиляции (§7.3). Каждая хост-система также определяет, какие наблюдаемые единицы компиляции ассоциированы с модулем. Наблюдаемость единиц компиляции, связанных с модулем, определяет, какие модули наблюдаемы (§7.7.3) и какие пакеты видны внутри этих модулей (§7.4.3).

Хост-система свободна определить, что единица компиляции, содержащая объявление модуля, на самом деле не является наблюдаемой и, следовательно, не связана с объявленным в ней модулем. Это позволяет компилятору выбрать, какой каталог на modulesourcepath "действительно" является воплощением данного модуля. Однако, если хост-система определяет, что единица компиляции, содержащая объявление модуля, является наблюдаемой, то §7.4.3 предписывает, что единица компиляции должна быть связана с объявленным в ней модулем, а не с каким-либо другим модулем.

Хост-система свободна определить, что единица компиляции, содержащая объявление типа, (во-первых) наблюдаема и (во-вторых) связана с безымянным модулем или автоматическим модулем — несмотря на то, что в любой наблюдаемой или иной единице компиляции нет объявления безымянного или автоматического модуля.

В простых реализациях Java SE Platform пакеты и единицы компиляции могут храниться в локальной файловой системе. Другие реализации могут хранить их с помощью распределённой файловой системы или какой-либо базы данных.

Если хост-система хранит пакеты и единицы компиляции в базе данных, то база данных не должна накладывать дополнительные ограничения (§7.6) на единицы компиляции, допустимые в реализациях на основе файлов.

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

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

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

Каталог может содержать следующие непосредственные подкаталоги:

com
gls
jag
java
wnj

где каталог java будет содержать пакеты Java SE Platform; каталоги jag, gls и wnj могут содержать пакеты, созданные тремя из авторов этого спецификации для личного использования и совместного использования в этой небольшой группе; и каталог com будет содержать пакеты, полученные от компаний, которые использовали соглашения, описанные в §6.1, для генерации уникальных имён для своих пакетов.

Продолжая пример, каталог java будет содержать, среди прочего, следующие подкаталоги:

applet
awt
io
lang
net
util

соответствующие пакетам java.applet, java.awt, java.io, java.lang, java.net и java.util, которые определены как часть API Java SE Platform.

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

BitSet.java        Observable.java
BitSet.class       Observable.class
Date.java          Observer.java
Date.class         Observer.class
...

где каждый из файлов .java содержит исходный код единицы компиляции (§7.3), содержащей определение класса или интерфейса, двоичная скомпилированная форма которого содержится в соответствующем файле .class.

При этой простой организации пакетов реализация Java SE Platform преобразует имя пакета в путь к файлу путём конкатенации компонентов имени пакета, помещая разделитель имени файла (индикатор каталога) между соседними компонентами.

Например, если эта простая организация используется в операционной системе, где разделитель имени файла — /, имя пакета:

jag.scrabble.board

будет преобразовано в имя каталога:

jag/scrabble/board

Компонент имени пакета или имя класса может содержать символ, который не может корректно отображаться в обычном имени каталога файловой системы хоста, например, символ Юникода в системе, которая допускает только символы ASCII в именах файлов. В качестве соглашения, символ может быть экранирован, например, с помощью символа @, за которым следуют четыре шестнадцатеричных цифры, задающие числовое значение символа, как в экранировании \uxxxx (§3.3).

В соответствии с этим соглашением, имя пакета:

children.activities.crafts.papierM\u00e2ch\u00e9

которое также можно записать с полным Юникодом:

children.activities.crafts.papierMâché

может быть отображено в имя каталога:

children/activities/crafts/papierM@00e2ch@00e9

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

7.3. Единицы компиляции

CompilationUnit — это целевой символ (§2.1) для синтаксической грамматики (§2.3) программ на Java. Он определяется следующим производством:

CompilationUnit:
OrdinaryCompilationUnit
ModularCompilationUnit
OrdinaryCompilationUnit:
[PackageDeclaration] {Объявление импорта} {Объявление типа}
ModularCompilationUnit:
{Объявление импорта} Объявление модуля

Обычная единица компиляции состоит из трёх частей, каждая из которых является необязательной:

  • Объявление пакета (§7.4), задающее полное имя (§6.7) пакета, к которому принадлежит единица компиляции.

    Единица компиляции, у которой нет объявления пакета, является частью безымянного пакета (§7.4.2).

  • Объявления импорта (§7.5), которые позволяют ссылаться на типы из других пакетов и члены типов с помощью их простых имён.
  • Объявления типов верхнего уровня (§7.6) типов классов и интерфейсов.

Модульная единица компиляции состоит из объявления модуля (§7.7), которое необязательно предшествует объявлениям импорта. Объявления импорта позволяют ссылаться на типы из пакетов в этом модуле и других модулей, а также члены типов с помощью их простых имён внутри объявления модуля.

Каждая единица компиляции неявно импортирует каждое имя типа, объявленное в предопределённом пакете public, как будто объявление import java.lang.*; помещено в начале каждой единицы компиляции сразу после объявления пакета. В результате имена всех этих типов доступны как простые имена в каждой единице компиляции.

Система-хост определяет, какие единицы компиляции являются наблюдаемыми, за исключением единиц компиляции в предопределённом пакете java и его подпакетов lang и io, которые всегда наблюдаемы.

Каждая наблюдаемая единица компиляции может быть связана с модулем следующим образом:

  • Система-хост может определить, что наблюдаемая обычная единица компиляции связана с модулем, выбранным системой-хостом, за исключением обычных единиц компиляции в предопределённом пакете java и его подпакетов lang и io, которые все связаны с модулем java.base.

  • Система-хост должна определить, что наблюдаемая модульная единица компиляции связана с модулем, объявленным модульной единицей компиляции.

Наблюдаемость единицы компиляции влияет на наблюдаемость её пакета (§7.4.3), а связывание наблюдаемой единицы компиляции с модулем влияет на наблюдаемость этого модуля (§7.7.6).

При компиляции модульных и обычных единиц компиляции, связанных с модулем M, система-хост должна соблюдать зависимости, указанные в объявлении M. В частности, система-хост должна ограничить наблюдаемые обычные единицы компиляции только теми, которые видимы для M. Обычные единицы компиляции, видимые для M, представляют собой наблюдаемые обычные единицы компиляции, связанные с модулями, которые читаются M. Модули, читаемые M, задаются результатом разрешения, как описано в спецификации пакета java.lang.module, с M в качестве единственного корневого модуля. Система-хост должна выполнить разрешение, чтобы определить модули, читаемые M; это ошибка времени компиляции, если разрешение терпит неудачу по любой причине, описанной в спецификации пакета java.lang.module.

Отношение читаемости рефлексивно, поэтому M читает сам себя, и, следовательно, все модульные и обычные единицы компиляции, связанные с M, видимы для M.

Модули, читаемые M, управляют пакетами, которые уникально видимы для M (§7.4.3), что, в свою очередь, управляет как пакетами верхнего уровня в области видимости, так и значением имён пакетов для кода в модульных и обычных единицах компиляции, связанных с M (§6.3, §6.5.3, §6.5.5).

Приведённые выше правила гарантируют, что имена пакетов/типов, используемые в аннотациях в модульной единице компиляции (в частности, аннотации, применённые к объявлению модуля), интерпретируются так, как будто они появились в обычной единице компиляции, связанной с модулем.

Типы, объявленные в различных обычных единицах компиляции, могут ссылаться друг на друга, в том числе циклически. Компилятор Java должен организовать компиляцию всех таких типов одновременно.

7.4. Декларации пакетов

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

7.4.1. Именованные пакеты

Декларация пакета в обычном компиляционном блоке указывает имя (§6.2) пакета, к которому принадлежит компиляционный блок.

PackageDeclaration:
{МодификаторПакета} package Идентификатор {. Идентификатор} ;
PackageModifier:
Аннотация

Имя пакета, упомянутое в декларации package, должно быть полным квалифицированным именем пакета (§6.7).

Область действия и перекрытие декларации пакета указаны в §6.3 и §6.4.

Правила для модификаторов аннотаций в декларации пакета указаны в §9.7.4 и §9.7.5.

Разрешается не более одной декларации package пакета с аннотациями для данного пакета.

Способ обеспечения этого ограничения должен по необходимости варьироваться от реализации к реализации. Следующая схема настоятельно рекомендуется для реализаций, основанных на файловой системе: Единственная аннотированная декларация package, если она существует, размещается в исходном файле под названием package-info.java в каталоге, содержащем исходные файлы пакета. Этот файл не содержит исходный код класса package-info; на самом деле это было бы незаконно, так как package-info не является допустимым идентификатором. Как правило, package-info.java содержит только декларацию package, непосредственно перед которой идут аннотации к пакету. Хотя файл технически мог бы содержать исходный код одного или нескольких классов с доступом к пакету, это было бы очень ненадлежащей практикой.

Рекомендуется, чтобы package-info.java, если он присутствует, заменял package.html для систем генерации документации javadoc и аналогичных систем. Если этот файл присутствует, инструмент генерации документации должен искать комментарий к документации пакета, непосредственно предшествующий (возможно, аннотированной) декларации package в package-info.java. Таким образом, package-info.java становится единственным хранилищем аннотаций и документации на уровне пакета. Если в будущем потребуется добавить любую другую информацию на уровне пакета, этот файл станет удобным местом для этой информации.

7.4.2. Пакеты без имени

Обычный компиляционный блок, не имеющий декларации package, является частью пакета без имени.

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

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

Реализация платформы Java SE должна поддерживать как минимум один пакет без имени. Реализация может поддерживать более одного пакета без имени, но это не обязательно. Какие обычные компиляционные блоки находятся в каждом пакете без имени, определяется системной средой.

Системная среда должна связывать обычные компиляционные блоки в пакете без имени с модулем без имени (§7.7.5), а не с именованным модулем.

Пример 7.4.2-1. Пакет без имени

Компиляционный блок:

class FirstCall {
    public static void main(String[] args) {
        System.out.println("Mr. Watson, come here. "
                           + "I want you.");
    }
}

определяет очень простой компиляционный блок как часть пакета без имени.


В реализациях платформы Java SE, использующих иерархическую файловую систему для хранения пакетов, типичная стратегия состоит в том, чтобы связать пакет без имени с каждым каталогом; только один пакет без имени виден одновременно, а именно тот, который связан с "текущей рабочей директорией". Точное значение "текущей рабочей директории" зависит от системной среды.

7.4.3. Наблюдаемость и видимость пакетов

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

  • Обычный компиляционный блок, содержащий декларацию пакета, наблюдаем (§7.3).

  • Подпакет пакета наблюдаем.

Пакеты java, java.lang и java.io всегда наблюдаемы.

Это можно заключить из правила выше и из правил наблюдаемых компиляционных блоков следующим образом. Предварительно определенный пакет java.lang объявляет класс Object, поэтому компиляционный блок для Object всегда наблюдаем (§7.3). Следовательно, пакет java.lang наблюдаем, и пакет java тоже. Кроме того, поскольку Object наблюдаем, тип массива Object[] неявно существует. Его суперинтерфейс java.io.Serializable (§10.1) также существует, следовательно, пакет java.io наблюдаем.

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

Видимость пакета подразумевает, что пакет наблюдаем полезным способом для данного модуля. Как правило, нет смысла знать, что пакет P наблюдаем только потому, что подпакет P.Q наблюдаем. Например, предположим, что P.Q наблюдаем (в модуле M1) и P.R наблюдаем (в модуле M2); тогда P наблюдаем, но где? В M1, или M2, или в обоих? Вопрос избыточен; во время компиляции модуля N, который требует только M1, важно, что P.Q наблюдаем, но не важно, что P наблюдаем.

Пакет единственно видим для модуля M тогда и только тогда, когда выполняется одно из следующих условий:

  • Обычный компиляционный блок, связанный с M, содержит декларацию пакета, и M не считывает никакой другой модуль, который экспортирует пакет в M.

  • Ни один обычный компиляционный блок, связанный с M, не содержит декларацию пакета, и M считывает ровно один другой модуль, который экспортирует пакет в M.

7.5. Декларации импорта

Декларация импорта позволяет обращаться к именованному типу или static члену с помощью простого имени (§6.2), состоящего из одного идентификатора.

Без использования соответствующей декларации импорта единственный способ обратиться к типу, объявленному в другом пакете, или static члену другого типа, заключается в использовании полных квалифицированных имён (§6.7).

ImportDeclaration:
SingleTypeImportDeclaration
TypeImportOnDemandDeclaration
SingleStaticImportDeclaration
StaticImportOnDemandDeclaration
  • Декларация импорта одного типа (§7.5.1) импортирует один именованный тип, указав его каноническое имя (§6.7).

  • Декларация импорта всех типов (§7.5.2) импортирует все доступные типы именованного типа или именованного пакета по мере необходимости, указав каноническое имя типа или пакета.

  • Декларация импорта одного статического члена (§7.5.3) импортирует все доступные static члены с заданным именем из типа, указав его каноническое имя.

  • Декларация импорта всех статических членов (§7.5.4) импортирует все доступные static члены именованного типа по мере необходимости, указав каноническое имя типа.

Область действия и перекрытие импортированного типа или члена задаются в §6.3 и §6.4.

Декларация import делает типы или члены доступными по их простым именам только в пределах единицы компиляции, которая фактически содержит декларацию import. Область действия типа(ов) или члена(ов), введённых декларацией import, специально не включает другие единицы компиляции в том же пакете, другие декларации import в текущей единице компиляции или декларацию package в текущей единице компиляции (за исключением аннотаций декларации package).

7.5.1. Декларации импорта одного типа

Декларация импорта одного типа импортирует один тип, указав его каноническое имя, сделав его доступным под простым именем в модулях, классах и интерфейсах единицы компиляции, в которой появляется декларация импорта одного типа.

SingleTypeImportDeclaration:
import TypeName ;

TypeName должен быть каноническим именем типа класса, типа интерфейса, типа перечисления или типа аннотации (§6.7).

Тип должен быть членом именованного пакета или членом типа, внешний лексически охватывающий тип объявления (§8.1.3) которого является членом именованного пакета; в противном случае произойдёт ошибка компиляции.

Ошибка компиляции возникает, если именованный тип недоступен (§6.6).

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

Если тип, импортированный декларацией импорта одного типа, объявлен в единице компиляции, содержащей декларацию import, то декларация import игнорируется.

Если декларация импорта одного типа импортирует тип с простым именем n, а единица компиляции также объявляет тип верхнего уровня (§7.6), простое имя которого равно n, возникает ошибка компиляции.

Если единица компиляции содержит как декларацию импорта одного типа, импортирующую тип с простым именем n, так и декларацию импорта одного статического члена (§7.5.3), импортирующую тип с простым именем n, возникает ошибка компиляции, за исключением случая, когда два типа являются одним и тем же типом, в этом случае дублирующая декларация игнорируется.

Пример 7.5.1-1. Импорт одного типа


import java.util.Vector;

делает простое имя Vector доступным в объявлениях классов и интерфейсов в единице компиляции. Таким образом, простое имя Vector ссылается на объявление типа Vector в пакете java.util во всех местах, где оно не скрывается (§6.4.1) или затеняется (§6.4.2) объявлением поля, параметра, локальной переменной или вложенного типа с тем же именем.

Обратите внимание, что фактическое объявление java.util.Vector является обобщённым (§8.1.2). После импорта имя Vector может использоваться без квалификации в параметризованном типе, таком как Vector<String>, или как тип без параметров Vector. Сопутствующим ограничением декларации import является то, что вложенный тип, объявленный внутри обобщённого объявления типа, может быть импортирован, но его внешний тип всегда стирается.


Пример 7.5.1-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; }


Пример 7.5.1-3. Отсутствие импорта подпакета

Обратите внимание, что декларация import не может импортировать подпакет, только тип.

Например, попытка импортировать java.util и затем использование имени util.Random для ссылки на тип java.util.Random не сработает:


import java.util;
class Test { util.Random generator; }
  // incorrect: compile-time error


Пример 7.5.1-4. Импорт имени типа, которое также является именем пакета

Имена пакетов и имена типов обычно различаются в соответствии с правилами именования, описанными в §6.1. Тем не менее, в искусственном примере, где есть нестандартно названный пакет Vector, который объявляет общедоступный класс с именем Mosquito:

package Vector;
public class Mosquito { int capacity; }

а затем единица компиляции:

package strange;
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());
    }
}

декларация импорта одного типа, импортирующая класс Vector из пакета java.util, не препятствует появлению имени пакета Vector и его правильному распознаванию в последующих декларациях import. Пример компилируется и выводит:

class java.util.Vector
class Vector.Mosquito

7.5.2. Декларации импорта типов по требованию

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

TypeImportOnDemandDeclaration:
import ИмяПакетаИлиТип . * ;

ИмяПакетаИлиТип должен быть каноническим именем (§6.7) пакета, класса, интерфейса, перечисления или аннотации.

Если ИмяПакетаИлиТип обозначает тип (§6.5.4), то этот тип должен быть членом именованного пакета или членом типа, внешняя лексически окружающая декларация типа которого (§8.1.3) является членом именованного пакета; в противном случае возникает ошибка компиляции.

Если именованный пакет не виден в текущем модуле (§7.4.3), или если именованный тип недоступен (§6.6), возникает ошибка компиляции.

Ошибка компиляции не возникает, если в декларации импорта типов по требованию указан либо java.lang, либо пакет текущей единицы компиляции. В таких случаях декларация импорта типов по требованию игнорируется.

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

Если единица компиляции содержит как декларацию импорта типов по требованию, так и декларацию статического импорта по требованию (§7.5.4), которые указывают на один и тот же тип, то эффект такой, как если бы static типы-члены этого типа (§8.5, §9.5) были импортированы только один раз.

Пример 7.5.2-1. Импорт типов по требованию


import java.util.*;

приводит к тому, что простые имена всех public типов, объявленных в пакете java.util, становятся доступными внутри деклараций классов и интерфейсов единицы компиляции. Таким образом, простое имя Vector ссылается на тип Vector в пакете java.util во всех местах единицы компиляции, где эта декларация типа не затенена (§6.4.1) или скрыта (§6.4.2).

Декларация может быть затенена декларацией импорта единственного типа типа, простое имя которого - Vector; типом с именем Vector, объявленным в пакете, к которому принадлежит единица компиляции; или любыми вложенными классами или интерфейсами.

Декларация может быть скрыта декларацией поля, параметра или локальной переменной с именем Vector.

(Вряд ли какие-либо из этих условий будут выполняться.)


7.5.3. Декларации одиночного статического импорта

Декларация одиночного статического импорта импортирует все доступные static члены с заданным простым именем из типа. Это делает эти static члены доступными под их простым именем в модуле, классе и интерфейсе деклараций единицы компиляции, в которой появляется декларация одиночного статического импорта.

SingleStaticImportDeclaration:
import static ИмяТипа . Идентификатор ;

ИмяТипа должен быть каноническим именем (§6.7) класса, интерфейса, перечисления или аннотации.

Тип должен быть членом именованного пакета или членом типа, внешняя лексически окружающая декларация типа которого (§8.1.3) является членом именованного пакета; в противном случае возникает ошибка компиляции.

Ошибка компиляции возникает, если указанный тип недоступен (§6.6).

Идентификатор должен указывать на по крайней мере один static член указанного типа. Ошибка компиляции возникает, если члена с таким именем нет, или если все указанные члены недоступны.

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

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

Если декларация одиночного статического импорта импортирует тип с простым именем n, а единица компиляции также объявляет тип верхнего уровня (§7.6), простое имя которого n, возникает ошибка компиляции.

Если единица компиляции содержит как декларацию одиночного статического импорта, импортирующую тип с простым именем n, так и декларацию одиночного импорта типа (§7.5.1), импортирующую тип с простым именем n, возникает ошибка компиляции, если эти типы не одинаковые, в противном случае дублирующая декларация игнорируется.

7.5.4. Декларации статического импорта по требованию

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

StaticImportOnDemandDeclaration:
import static ИмяТипа . * ;

ИмяТипа должен быть каноническим именем (§6.7) класса, интерфейса, перечисления или аннотации.

Тип должен быть членом именованного пакета или членом типа, внешняя лексически окружающая декларация типа которого (§8.1.3) является членом именованного пакета; в противном случае возникает ошибка компиляции.

Ошибка компиляции возникает, если указанный тип недоступен (§6.6).

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

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

Допустимо, чтобы одна декларация статического импорта по требованию импортировала несколько полей или типов с одинаковым именем, или несколько методов с одинаковым именем и сигнатурой. Это происходит, когда указанный тип наследует несколько полей, типов-членов или методов, все с одинаковым именем, от своих предков.

Если единица компиляции содержит как декларацию статического импорта по требованию, так и декларацию импорта типов по требованию (§7.5.2), которые указывают на один и тот же тип, то эффект такой, как если бы static типы-члены этого типа (§8.5, §9.5) были импортированы только один раз.

7.6. Объявления типов верхнего уровня

Объявление типа верхнего уровня объявляет тип класса верхнего уровня (§8 (Классы)) или тип интерфейса верхнего уровня (§9 (Интерфейсы)).

TypeDeclaration:
ClassDeclaration
InterfaceDeclaration
;

Дополнительные маркеры ";" на уровне объявлений типов в единице компиляции не влияют на значение единицы компиляции. В языке программирования Java разрешается использовать дополнительные точки с запятой исключительно как уступка программистам C++, которые привыкли ставить ";" после объявления класса. Их не следует использовать в новом коде Java.

При отсутствии модификатора доступа тип верхнего уровня имеет доступ к пакету: он доступен только в обычных единицах компиляции пакета, в котором он объявлен (§6.6.1). Тип может быть объявлен public, чтобы предоставить доступ к типу из кода в других пакетах одного модуля и, возможно, из кода в пакетах других модулей.

Ошибка времени компиляции, если объявление типа верхнего уровня содержит любой из следующих модификаторов доступа: protected, private или static.

Ошибка времени компиляции, если имя типа верхнего уровня появляется как имя любого другого типа класса или интерфейса верхнего уровня, объявленного в том же пакете.

Область видимости и перекрытие типа верхнего уровня указаны в §6.3 и §6.4.

Полное имя типа верхнего уровня указано в §6.7.

Пример 7.6-1. Конфликтующие объявления типов верхнего уровня

package test;
import java.util.Vector;
class Point {
    int x, y;
}
interface Point {  // compile-time error #1
    int getR();
    int getTheta();
}
class Vector { Point[] pts; }  // compile-time error #2

Здесь первая ошибка времени компиляции вызвана дублированием объявления имени Point как класса, так и интерфейса в одном пакете. Вторая ошибка времени компиляции — попытка объявить имя Vector как типом класса, так и объявлением импорта одного типа.

Однако следует отметить, что это не ошибка, если имя класса также обозначает тип, который иначе мог бы быть импортирован объявлением импорта по требованию (§7.5.2) в единице компиляции (§7.3), содержащей объявление класса. Таким образом, в этой программе:

package test;
import java.util.*;
class Vector {}  // not a compile-time error

объявление класса Vector разрешено, даже если есть также класс java.util.Vector. В пределах этой единицы компиляции простое имя Vector относится к классу test.Vector, а не к java.util.Vector (к которому все же можно обратиться из кода в единице компиляции, но только по его полному имени).


Пример 7.6-2. Область видимости типов верхнего уровня

package points;
class Point {
    int x, y;           // coordinates
    PointColor color;   // color of this point
    Point next;         // next point with this color
    static int nPoints;
}
class PointColor {
    Point first;        // first point with this color
    PointColor(int color) { this.color = color; }
    private int color;  // color components
}

Эта программа определяет два класса, которые используют друг друга в объявлениях своих членов класса. Поскольку типы классов Point и PointColor имеют все объявления типов в пакете points, включая все в текущей единице компиляции, в качестве своей области видимости, эта программа компилируется правильно. То есть, ссылка вперёд не является проблемой.


Пример 7.6-3. Полные имена


class Point { int x, y; }

В этом коде класс Point объявлен в единице компиляции без объявления package, и поэтому Point — это его полное имя, тогда как в коде:


package vista;
class Point { int x, y; }

полное имя класса Point — vista.Point. (Имя пакета vista подходит для локального или личного использования; если пакет предназначен для широкого распространения, лучше дать ему уникальное имя пакета (§6.1).)


Реализация платформы Java SE должна отслеживать типы в пакетах по комбинации имён их окружающих модулей и их бинарных имён (§13.1). Несколько способов именования типа необходимо расширить до бинарных имён, чтобы убедиться, что такие имена понимаются как ссылки на один и тот же тип.

Например, если единица компиляции содержит объявление импорта одного типа (§7.5.1):


import java.util.Vector;

то в пределах этой единицы компиляции простое имя Vector и полное имя java.util.Vector относятся к одному и тому же типу.

Если и только если пакеты хранятся в файловой системе (§7.2), система хоста может выбрать принудительное требование, что это ошибка времени компиляции, если тип не найден в файле под именем, составленным из имени типа и расширения (таких как .java или .jav), если верно одно из следующих утверждений:

  • К типу обращаются код в других обычных единицах компиляции пакета, в котором тип объявлен.

  • Тип объявлен public (и поэтому потенциально доступен из кода в других пакетах).

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

Например, исходный код типа public wet.sprocket.Toad будет найден в файле Toad.java в каталоге wet/sprocket, а соответствующий объектный код будет найден в файле Toad.class в том же каталоге.

7.7. Декларации модулей

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

«Зависимость» — это то, что выражается с помощью директивы requires, независимо от того, существует ли модуль с именем, указанным в директиве. «Зависимости» — это наблюдаемый перечень модулей, определяемый разрешением (как описано в разделе java.lang.module спецификации пакета) для данной директивы requires. Как правило, правила языка программирования Java больше интересуются зависимостями, чем зависимостями.

ModuleDeclaration:
{Annotation} [open] module Identifier {. Identifier} { {ModuleDirective} }

Декларация модуля вводит имя модуля, которое может использоваться в других декларациях модулей для выражения взаимоотношений между модулями. Имя модуля состоит из одного или нескольких идентификаторов Java (§3.8), разделенных токенами «.».

Существуют два типа модулей: обычные модули и открытые модули. Тип модуля определяет характер доступа к типам модуля и членам этих типов для кода за пределами модуля.

Обычный модуль без модификатора open предоставляет доступ во время компиляции и выполнения только к типам в тех пакетах, которые явно экспортированы.

Открытый модуль с модификатором open предоставляет доступ во время компиляции только к типам в тех пакетах, которые явно экспортированы, но предоставляет доступ во время выполнения к типам во всех своих пакетах, как если бы все пакеты были экспортированы.

Для кода вне модуля (независимо от того, является ли модуль обычным или открытым) предоставленный доступ во время компиляции или выполнения к типам в экспортированных пакетах модуля относится конкретно к public и protected типам в этих пакетах, а также к public и protected членам этих типов (§6.6). Доступ во время компиляции и выполнения к типам или их членам в пакетах, которые не экспортированы, не предоставляется. Код внутри модуля может получить доступ к public и protected типам и к public и protected членам этих типов во всех пакетах модуля как во время компиляции, так и во время выполнения.

Отдельно от доступа во время компиляции и выполнения платформа Java SE предоставляет рефлексивный доступ через API ядра рефлексии (§1.4). Обычный модуль предоставляет рефлексивный доступ к типам только в тех пакетах, которые явно экспортированы или явно открыты (или оба). Открытый модуль предоставляет рефлексивный доступ к типам во всех своих пакетах, как если бы все пакеты были открыты.

Для кода вне обычного модуля предоставленный рефлексивный доступ к типам в экспортированных (и не открытых) пакетах модуля относится конкретно к public и protected типам в этих пакетах, а также к public и protected членам этих типов. Предоставленный рефлексивный доступ к типам в открытых пакетах модуля (открытых или нет) относится ко всем типам в этих пакетах и всем членам этих типов. Рефлексивный доступ к типам или их членам в пакетах, которые не экспортированы или не открыты, не предоставляется. Код внутри модуля получает рефлексивный доступ ко всем типам и всем их членам во всех пакетах модуля.

Для кода вне открытого модуля предоставленный рефлексивный доступ к типам в открытых пакетах модуля (то есть ко всем пакетам модуля) относится ко всем типам в этих пакетах и всем членам этих типов. Код внутри модуля получает рефлексивный доступ ко всем типам и всем их членам во всех пакетах модуля.

Директивы декларации модуля задают зависимости модуля от других модулей (через requires, §7.7.1), пакеты, которые он предоставляет другим модулям (через exports и opens, §7.7.2), используемые им службы (через uses, §7.7.3) и предоставляемые им службы (через provides, §7.7.4).

ModuleDirective:
requires {RequiresModifier} ModuleName ;
exports PackageName [to ModuleName {, ModuleName}] ;
opens PackageName [to ModuleName {, ModuleName}] ;
uses TypeName ;
provides TypeName with TypeName {, TypeName} ;
RequiresModifier:
(one of)
transitive static

Если и только если пакеты хранятся в файловой системе (§7.2), система хоста может выбрать применение ограничения, согласно которому в случае отсутствия декларации модуля в файле с именем, составленным из module-info плюс расширения (такого как .java или .jav), это будет считаться ошибкой во время компиляции.

Для повышения понимания принято, но не обязательно, группировать директивы декларации модуля таким образом, чтобы директивы requires, относящиеся к модулям, визуально отличались от директив exports и opens, относящихся к пакетам, и от директив uses и provides, относящихся к услугам. Например:

module com.example.foo {
    requires com.example.foo.http;
    requires java.logging;

    requires transitive com.example.foo.network;

    exports com.example.foo.bar;
    exports com.example.foo.internal to com.example.foo.probe;

    opens com.example.foo.quux;
    opens com.example.foo.internal to com.example.foo.network,
                                      com.example.foo.probe;

    uses com.example.foo.spi.Intf;
    provides com.example.foo.spi.Intf with com.example.foo.Impl;
}

Директивы opens можно избежать, если модуль открыт:

open module com.example.foo {
    requires com.example.foo.http;
    requires java.logging;

    requires transitive com.example.foo.network;
 
    exports com.example.foo.bar;
    exports com.example.foo.internal to com.example.foo.probe;

    uses com.example.foo.spi.Intf;
    provides com.example.foo.spi.Intf with com.example.foo.Impl;
}

Инструменты разработки для языка программирования Java рекомендуются для выделения директив requires transitive и директив exports без квалификатора, так как они представляют собой основной API модуля.

7.7.1. Зависимости

Директива requires указывает имя модуля, от которого текущий модуль зависит.

Директива requires не должна присутствовать в объявлении модуля java.base, так как это базовый модуль, у которого нет зависимостей (§8.1.4), что приведёт к ошибке компиляции.

Если объявление модуля не выражает зависимость от модуля java.base, и сам модуль не является java.base, то модуль неявно зависит от модуля java.base.

Ключевое слово requires может быть дополнено модификатором transitive. Это приводит к тому, что любой модуль, зависящий от текущего модуля, неявно зависит от модуля, указанного в директиве requires transitive.

Ключевое слово requires может быть дополнено модификатором static. Это указывает, что зависимость, обязательная на стадии компиляции, необязательна во время выполнения.

Если объявление модуля выражает зависимость от модуля java.base, и сам модуль не является java.base, то наличие модификатора после ключевого слова requires является ошибкой компиляции.

Если более одной директивы requires в объявлении модуля указывают на одно и то же имя модуля, это ошибка компиляции.

Если разрешение, как описано в спецификации пакета java.lang.module, с текущим модулем в качестве единственного корневого модуля, терпит неудачу по любой из причин, описанных в спецификации пакета java.lang.module, это ошибка компиляции.

Например, если директива requires указывает на неочевидный модуль, или если текущий модуль напрямую или косвенно указывает на зависимость от самого себя.

Если разрешение прошло успешно, то его результат указывает модули, которые читаются текущим модулем. Модули, читаемые текущим модулем, определяют, какие обычные единицы компиляции видны текущему модулю (§7.3). Типы, объявленные в этих обычных единицах компиляции (и только в них), могут быть доступны коду в текущем модуле (§6.6).

Java SE Platform различает именованные модули, которые явно объявлены (то есть с помощью объявления модуля), и именованные модули, которые неявно объявлены (то есть автоматические модули). Однако язык программирования Java не отображает это различие: директивы requires ссылаются на именованные модули без учёта того, явно они объявлены или неявно.

Хотя автоматические модули удобны для миграции, они ненадёжны в том смысле, что их имена и экспортированные пакеты могут измениться, когда их авторы превратят их в явно объявленные модули. Компилятор Java рекомендуется выдавать предупреждение, если директива requires ссылается на автоматический модуль. Особенно сильное предупреждение рекомендуется, если модификатор transitive присутствует в директиве.

Пример 7.1.1-1. Разрешение директив requires transitive

Предположим, что существуют четыре объявления модулей следующим образом:

module m.A {
    requires m.B;
}

module m.B {
    requires transitive m.C;
}

module m.C {
    requires transitive m.D;
}

module m.D {
    exports p;
}

где пакет p, экспортированный модулем m.D, объявлен следующим образом:

package p;
public class Point {}

и где пакет client в модуле m.A ссылается на тип public Point в экспортированном пакете p:

package client;
import p.Point;
public class Test {
    public static void main(String[] args) {
        System.out.println(new Point());
    }
}

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

javac --module-source-path . -d . --module m.D
javac --module-source-path . -d . --module m.C
javac --module-source-path . -d . --module m.B
javac --module-source-path . -d . --module m.A

Программа client.Test может быть запущена следующим образом:

java --module-path . --module m.A/client.Test

Ссылка из кода в модуле m.A на экспортированный тип public Point в модуле m.D допустима, так как m.A читает m.D, а m.D экспортирует пакет, содержащий Point. Разрешение определяет, что модуль m.A читает m.D следующим образом:

  • m.A requires m.B и поэтому читает m.B.

  • Так как m.A читает m.B, и так как m.B requires transitive m.C, разрешение определяет, что m.A читает m.C.

  • Затем, так как m.A читает m.C, и так как m.C requires transitive m.D, разрешение определяет, что m.A читает m.D.

По сути, модуль может читать другой модуль через несколько уровней зависимости, чтобы поддерживать произвольное количество рефакторинга. После выпуска модуля для повторного использования (через requires), автор модуля обязуется к его имени и API, но свободен переработать его содержимое в другие модули, которые использует исходный модуль (через requires transitive) для пользы потребителей. В приведённом выше примере пакет p мог быть изначально экспортирован модулем m.B (следовательно, m.A requires m.B), но рефакторинг привёл к перемещению части содержимого m.B в m.C и m.D. Используя цепочку директив requires transitive, семейство модулей m.B, m.C и m.D могут сохранить доступ к пакету p для кода в m.A без принудительного внесения изменений в директивы requires модуля m.A. Обратите внимание, что пакет p в модуле m.D не «переэкспортируется» модулями m.C и m.B; вместо этого модуль m.A непосредственно читает модуль m.D.


7.7.2. Экспортированные и открытые пакеты

Директива exports указывает имя пакета, который должен быть экспортирован текущим модулем. Для кода в других модулях это предоставляет доступ во время компиляции и выполнения к типам public и protected в пакете, а также к членам public и protected этих типов (§6.6). Также предоставляется рефлексивный доступ к этим типам и членам для кода в других модулях.

Директива opens указывает имя пакета, который должен быть открыт текущим модулем. Для кода в других модулях это предоставляет доступ во время выполнения, но не во время компиляции, к типам public и protected в пакете, а также к членам public и protected этих типов. Также предоставляется рефлексивный доступ ко всем типам в пакете и всем их членам для кода в других модулях.

Ошибка компиляции, если пакет, указанный в exports, не объявлен в единице компиляции, связанной с текущим модулем (§7.3).

Разрешено указывать в opens пакет, который не объявлен в единице компиляции, связанной с текущим модулем. (Если пакет объявлен в доступной единице компиляции, связанной с другим модулем, директива opens не влияет на этот другой модуль.)

Ошибка компиляции, если более одной директивы exports в объявлении модуля указывают на одно и то же имя пакета.

Ошибка компиляции, если более одной директивы opens в объявлении модуля указывают на одно и то же имя пакета.

Ошибка компиляции, если директива opens присутствует в объявлении открытого модуля.

Если у директивы exports или opens есть фрагмент to, то директива квалифицированная; в противном случае – неквалифицированная. Для квалифицированной директивы типы public и protected в пакете и их члены public и protected доступны только коду в модулях, указанных в фрагменте to. Модули, указанные во фрагменте to, называются друзьями текущего модуля. Для неквалифицированной директивы эти типы и их члены доступны коду в любом модуле.

Разрешено в фрагменте to директивы exports или opens указывать модуль, который не является очевидным (§7.7.6).

Ошибка компиляции, если фрагмент to данной директивы exports указывает одно и то же имя модуля более одного раза.

Ошибка компиляции, если фрагмент to данной директивы opens указывает одно и то же имя модуля более одного раза.

7.7.3. Использование сервисов

Директива uses указывает на сервис, для которого текущий модуль может обнаружить поставщиков через java.util.ServiceLoader.

Сервис должен быть типом класса, типом интерфейса или типом аннотации. Ошибка компиляции возникает, если директива uses указывает на тип перечисления (§8.9) в качестве сервиса.

Сервис может быть объявлен в текущем модуле или в другом модуле. Если сервис не объявлен в текущем модуле, он должен быть доступен коду в текущем модуле (§6.6), иначе произойдет ошибка компиляции.

Ошибка компиляции возникает, если более одной директивы uses в объявлении модуля указывает на один и тот же сервис.

7.7.4. Предоставление сервисов

Директива provides указывает на сервис, для которого в части with указан один или несколько поставщиков сервиса для java.util.ServiceLoader.

Сервис должен быть типом класса, типом интерфейса или типом аннотации. Ошибка компиляции возникает, если директива provides указывает на тип перечисления (§8.9) в качестве сервиса.

Сервис может быть объявлен в текущем модуле или в другом модуле. Если сервис не объявлен в текущем модуле, он должен быть доступен коду в текущем модуле (§6.6), иначе произойдет ошибка компиляции.

Каждый поставщик сервиса должен быть типом класса или типом интерфейса, который является public и является верхнеуровневым или вложенным static, иначе произойдет ошибка компиляции.

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

Если поставщик сервиса явно объявляет public конструктор без формальных параметров или неявно объявляет public конструктор по умолчанию (§8.8.9), то этот конструктор называется конструктором поставщика.

Если поставщик сервиса явно объявляет public static метод, называемый provider, без формальных параметров, то этот метод называется методом поставщика.

Если у поставщика сервиса есть метод поставщика, то его возвращаемый тип должен (i) либо быть объявлен в текущем модуле, либо быть объявлен в другом модуле и быть доступен коду в текущем модуле; и (ii) быть подтипом сервиса, указанного в директиве provides; иначе произойдет ошибка компиляции.

Хотя поставщик сервиса, указанный в директиве provides, должен быть объявлен в текущем модуле, его метод поставщика может иметь возвращаемый тип, объявленный в другом модуле. Также обратите внимание, что когда поставщик сервиса объявляет метод поставщика, сам поставщик сервиса не обязательно должен быть подтипом сервиса.

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

Ошибка компиляции возникает, если более одной директивы provides в объявлении модуля указывает на один и тот же сервис.

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

7.7.5. Безымянные модули

Наблюдаемый обычный модуль компиляции, который система хоста не связывает с именованным модулем (§7.3), связан с безымянным модулем.

Безымянные модули предоставляются платформой Java SE, признавая тот факт, что программы, разработанные до Java SE 9, не могли объявлять именованные модули. Кроме того, причины предоставления платформой Java SE безымянных пакетов (§7.4.2) в значительной степени применимы к безымянным модулям.

Реализация платформы Java SE должна поддерживать по крайней мере один безымянный модуль. Реализация может поддерживать более одного безымянного модуля, но это не требуется. Какие обычные модули компиляции связаны с каждым безымянным модулем, определяется системой хоста.

Система хоста может связать обычные модули компиляции в именованном пакете с безымянным модулем.

Правила для безымянных модулей разработаны для максимальной совместимости с именованными модулями следующим образом:

  • Безымянный модуль читает каждый наблюдаемый модуль (§7.7.6).

    В силу того, что обычный модуль компиляции, связанный с безымянным модулем, наблюдаем, связанный безымянный модуль также наблюдаем. Таким образом, если реализация платформы Java SE поддерживает более одного безымянного модуля, каждый безымянный модуль наблюдаем; и каждый безымянный модуль читает каждый безымянный модуль, включая себя.

    Однако важно понимать, что обычные модули компиляции безымянного модуля никогда не видимы для именованного модуля (§7.3), так как ни одна директива requires не может обеспечить чтение именованным модулем безымянного модуля. API базовых рефлексий платформы Java SE можно использовать для организации чтения безымянного модуля именованным модулем во время выполнения.

  • Безымянный модуль экспортирует каждый пакет, обычные модули компиляции которых связаны с этим безымянным модулем.

  • Безымянный модуль открывает каждый пакет, обычные модули компиляции которых связаны с этим безымянным модулем.

7.7.6. Наблюдаемость модуля

Модуль наблюдаем, если хотя бы одно из следующих условий истинно:

  • Модуль компиляции, содержащий объявление модуля, наблюдаем (§7.3).

  • Обычный модуль компиляции, связанный с модулем, наблюдаем.

© Oracle and/or its affiliates. All rights reserved.
Licensed under the Oracle Technology Network License Agreement.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API