このドキュメントでは、Java SE 23のプレビュー機能であるモジュール・インポート宣言をサポートするためのJava言語仕様に対する変更点について説明します。この機能の概要は、JEP 476を参照してください。
JEP 477で提案されたプレビュー機能の暗黙的に宣言されたクラスおよびインスタンスのmain
メソッドは、この機能に依存します。
変更は、JLSの既存のセクションについて説明しています。新しいテキストはこのように示され、削除されたテキストはこのように示されます。必要に応じて、説明と考察が端の方にグレーのボックスで囲まれて記載されています。
変更ログ:
2024-06-04: 欠落している更新をセクション3.9に追加しています
2024-05-07: JEP 477リンクで更新しました。
2024-04: 初稿
第3章: 字句構造
3.9 キーワード
ASCII文字で構成された51個の文字シーケンスは、キーワードとして使用するために予約されており、識別子(3.8)として使用することはできません。その他の同じくASCII文字で構成された17個の文字シーケンスは、出現するコンテキストによっては、キーワードや別のトークンとして解釈される可能性があります。
- Keyword:
- ReservedKeyword
- ContextualKeyword
- ReservedKeyword:
-
(1つの) #
abstract continue for new switch
assert default if package synchronized
boolean do goto private this
break double implements protected throw
byte else import public throws
case enum instanceof return transient
catch extends int short try
char final interface static void
class finally long strictfp volatile
const float native super while
_
(アンダースコア) - ContextualKeyword:
-
(1つの) #
exports opens requires uses yield
module permits sealed var
non-sealed provides to when
open record transitive with
キーワード
const
およびgoto
は、現在使用されていませんが、予約されています。これにより、これらのC++のキーワードがプログラムで誤って出現した場合にJavaコンパイラがより適切なエラー・メッセージを作成できるようになります。
キーワード
strictfp
は廃止されています。新しいコードには使用しないでください。
キーワード
_
(アンダースコア)は、識別子(6.1)のかわりに特定の宣言で使用できます。
true
およびfalse
はキーワードではなく、booleanリテラルです(3.10.3)。
null
はキーワードではなく、nullリテラルです(3.10.8)。
入力文字から入力要素への還元(3.5)の際に、コンテキスト・キーワードと概念的に一致する入力文字のシーケンスは、次の両方の条件が満たされる場合にのみ、コンテキスト・キーワードに還元されます。
シーケンスは、次のように、構文文法(2.3)の適切なコンテキストで指定された終端として認識されます。
module
およびopen
については、ModuleDeclaration (7.7)で終端として認識される場合。
exports
、opens
、provides
、requires
、to
、uses
およびwith
については、ModuleDirectiveで終端として認識される場合。transitive
については、RequiresModifierで終端として認識される場合。たとえば、シーケンス
requires
transitive
;
の認識では、RequiresModifierが使用されていないため、このtransitive
という用語はコンテキスト・キーワードではなく識別子に還元されます。var
については、LocalVariableType (14.4)またはLambdaParameterType (15.27.1)で終端として認識される場合。その他のコンテキストでは、識別子として
var
を使用しようとすると、var
はTypeIdentifier (3.8)ではないためにエラーが発生します。yield
については、YieldStatement (14.21)で終端として認識される場合。その他のコンテキストでは、識別子として
yield
を使用しようとすると、yield
はTypeIdentifierとUnqualifiedMethodIdentifierのどちらでもないためにエラーが発生します。record
については、RecordDeclaration (8.10)で終端として認識される場合。non-sealed
、permits
およびsealed
については、NormalClassDeclaration (8.1)またはNormalInterfaceDeclaration (9.1)で終端として認識される場合。when
については、Guard (14.11.1)で終端として認識される場合。
シーケンスの直前または直後に、JavaLetterOrDigitと一致する入力文字がない。
一般に、ソースコードで誤って空白を省略すると、「可能なかぎり長い変換」ルール(3.2)によって、入力文字のシーケンスが識別子としてトークン化されます。たとえば、12文字の入力文字シーケンス
p u b l i c s t a t i c
は、予約キーワードのpublic
およびstatic
としてではなく、常に識別子のpublicstatic
としてトークン化されます。2つのトークンを使用する場合は、それらを空白またはコメントで区切る必要があります。
前述のルールは、「可能なかぎり長い変換」ルールと連動して、コンテキスト・キーワードが現れるコンテキスト内で直感的な結果を生成します。たとえば、11文字の入力文字シーケンス
v a r f i l e n a m e
は、通常、識別子varfilename
としてトークン化されますが、ローカル変数宣言では、最初の3文字の入力文字は、前述のルールの最初の条件によって暫定的にコンテキスト・キーワードvar
として認識されます。ただし、シーケンス内の空白の不足を見落とすと、その次の8文字の入力文字を識別子filename
として認識することによる混乱が生じます。(これは、シーケンスが異なるコンテキストで異なるトークン化を経ることを意味します。ほとんどのコンテキストでは識別子ですが、ローカル変数宣言ではコンテキスト・キーワードと識別子です)。したがって、2番目の条件により、直後の入力文字のf
がJavaLetterOrDigitであるという理由で、コンテキスト・キーワードvar
の認識を防止します。そのため、シーケンスv a r f i l e n a m e
は、ローカル変数宣言の識別子varfilename
としてトークン化されます。
コンテキスト・キーワードの慎重な認識の別の例として、15文字の入力文字のシーケンス
n o n - s e a l e d c l a s s
について考えてみます。このシーケンスは、通常、識別子non
、演算子-
および識別子sealedclass
の3つのトークンに変換されますが、最初の条件が成立する通常のクラス宣言では、最初の10の入力文字は暫定的にコンテキスト・キーワードnon-sealed
として認識されます。シーケンスを3つの非キーワード・トークンではなく2つのキーワード・トークン(non-sealed
とclass
)に解釈されることを回避し、class
の前の空白を省略するプログラマに報酬を与えないようにするために、2番目の条件によってコンテキスト・キーワードの認識を防止します。そのため、シーケンスn o n - s e a l e d c l a s s
は、クラス宣言では3つのトークンとしてトークン化されます。
前述のルールでは、最初の条件は構文文法の詳細に依存しますが、Javaプログラミング言語のコンパイラは、入力プログラムを完全に解析することなくルールを実装できます。たとえば、コンテキスト・キーワードの有効な使用がキーワードとしてトークン化され、識別子の有効な使用が識別子としてトークン化されることがヒューリスティックで保証されているかぎり、ヒューリスティックを使用してトークナイザのコンテキスト状態を追跡できます。また、コンパイラでは常にコンテキスト・キーワードを識別子としてトークン化し、そうした識別子の特別な使用の認識は、それより後のフェーズに任せることもできます。
第6章: 名前
6.1 宣言
宣言は、次のいずれかのエンティティをプログラムに導入します:
module
宣言で宣言されたモジュール(7.7)package
宣言で宣言されたパッケージ(7.4)単一型インポート宣言、
またはオンデマンド型インポート宣言または単一モジュール・インポート宣言 (7.5.1、7.5.2、7.5.5)で宣言されているインポートされたクラスまたはインタフェース。単一静的インポート宣言またはオンデマンド静的インポート宣言で宣言された、インポートされた
static
メンバー(7.5.3、7.5.4)汎用クラス、インタフェース、メソッドまたはコンストラクタの宣言の一部として宣言された型パラメータ(8.1.2、9.1.2、8.4.4、8.8.4)
参照型のメンバー(8.2、9.2、8.9.3、9.6、10.7)で、次のいずれか:
フィールドで、次のいずれか:
メソッドで、次のいずれか:
enum定数(8.9.1)
レコード・コンポーネント(8.10.3)
仮パラメータで、次のいずれか:
try
文のcatch
句で宣言された例外ハンドラの例外パラメータ(14.20)ローカル変数で、次のいずれか:
ローカル・クラスまたはインタフェース(14.3)で、次のいずれか:
標準クラス宣言によって宣言されたローカル・クラス
enum宣言によって宣言されたローカル・クラス
レコード宣言によって宣言されたローカル・クラス
標準インタフェース宣言で宣言されたローカル・インタフェース
この項の残りの部分に変更はありません。
6.3 宣言のスコープ
宣言のスコープは、単純名を使用して、その宣言によって宣言されたエンティティを参照できるプログラム内の領域です(ただし、シャドウ化されていることが条件です) (6.4.1)。
宣言がプログラム内の特定のポイントでスコープ内にあるとされるのは、宣言のスコープにそのポイントが含まれる場合のみです。
観察可能な最上位パッケージ(7.4.3)の宣言のスコープは、パッケージが一意として表示されるモジュールに関連付けられたすべての観察可能なコンパイル・ユニットです(7.4.3)。
観察可能でないパッケージの宣言はスコープ内ではありません。
サブパッケージの宣言はスコープ内ではありません。
パッケージjava
は常にスコープ内にあります。
単一型インポート宣言(7.5.1)、またはオンデマンド型インポート宣言(7.5.2)または単一モジュール・インポート宣言(7.5.5)によってインポートされるクラスまたはインタフェースのスコープは、モジュール宣言(7.7)、およびimport
宣言が示されるコンパイル・ユニットのすべてのクラス宣言およびインタフェース宣言(8.1、9.1)、ならびにコンパイル・ユニットのモジュール宣言またはパッケージ宣言の注釈です。
単一静的インポート宣言(7.5.3)またはオンデマンド静的インポート宣言(7.5.4)によってインポートされるメンバーのスコープは、モジュール宣言、およびimport
宣言が出現するコンパイル・ユニットのすべてのクラス宣言およびインタフェース宣言、ならびにコンパイル・ユニットのモジュール宣言またはパッケージ宣言の注釈です。
最上位クラスまたはインタフェース(7.6)のスコープは、最上位クラスまたはインタフェースが宣言されているパッケージ内のすべてのクラス宣言およびインタフェース宣言です。
クラスまたはインタフェースCによって宣言または継承されたメンバーm (8.2、9.2)の宣言のスコープは、Cの本体全体(ネストされたクラスまたはインタフェースの宣言を含む)です。Cがレコード・クラスである場合、mのスコープには、さらにCのレコード宣言のヘッダーが含まれます。
メソッド(8.4.1)、コンストラクタ(8.8.1)またはラムダ式(15.27)の仮パラメータのスコープは、メソッド、コンストラクタまたはラムダ式の本体全体です。
クラスの型パラメータ(8.1.2)のスコープは、クラス宣言の型パラメータ・セクションと、クラス宣言のスーパークラス型またはスーパーインタフェース型の型パラメータ・セクション、およびクラス本体です。クラスがレコード・クラス(8.10)の場合、レコード・クラスの型パラメータのスコープには、レコード宣言(8.10.1)のヘッダーも追加で含まれます。
インタフェースの型パラメータ(9.1.2)のスコープは、インタフェース宣言の型パラメータ・セクションと、インタフェース宣言のスーパーインタフェース型の型パラメータ・セクション、およびインタフェース本体です。
メソッドの型パラメータ(8.4.4)のスコープは、メソッドの宣言全体で、型パラメータ・セクションを含みますが、メソッド修飾子は除きます。
コンストラクタの型パラメータ(8.8.4)のスコープは、コンストラクタの宣言全体で、型パラメータ・セクションを含みますが、コンストラクタ修飾子は除きます。
ブロック(14.2)で直接囲まれたローカル・クラスまたはインタフェース宣言のスコープは、直接囲んでいるブロックの残りの部分であり、そのローカル・クラスまたはインタフェース宣言自体を含みます。
switchブロック文グループ(14.11)で直接囲まれたローカル・クラスまたはインタフェース宣言のスコープは、直接囲んでいるswitchブロック文グループの残りの部分であり、そのローカル・クラスまたはインタフェース宣言自体を含みます。
ローカル変数宣言文(14.4.2)によってブロック内で宣言されたローカル変数のスコープは、そのブロックの残りの部分であり、宣言の独自のイニシャライザから始まり、ローカル変数宣言文の右側にある別の宣言子を含みます。
基本的なfor
文(14.14.1)のForInit部分で宣言されたローカル変数のスコープには、次がすべて含まれます。
それ自体のイニシャライザ
for
文のForInit部分の右側にある別の宣言子for
文のExpressionおよびForUpdate部分含まれている文
拡張されたfor
文(14.14.2)のヘッダーで宣言されたローカル変数のスコープは、含まれている文です。
try
-with-resources文(14.20.3)のリソース指定で宣言されたローカル変数のスコープは、リソース指定の右側にある残りの宣言、およびtry
-with-resources文に関連付けられたtry
ブロック全体です。
try
-with-resources文の翻訳は、前述のルールを示します。
try
文(14.20)のcatch
句で宣言された例外ハンドラのパラメータのスコープは、catch
に関連付けられたブロック全体です。
この項の残りの部分に変更はありません。
6.4 シャドウ化および不明瞭化
6.4.1 シャドウ化
一部の宣言は、同じ名前を持つ他の宣言によってそのスコープ内の一部でシャドウ化できます。この場合、単純名を使用して、宣言されたエンティティを参照することはできません。
シャドウ化は、非表示(8.3、8.4.8.2、8.5、9.3、9.5)とは異なります。非表示は、サブクラス内で宣言されているために継承されておらず、そうでなければ継承されていたメンバーにのみ適用されます。また、シャドウ化は不明瞭化(6.4.2)とも異なります。
nという名前の型の宣言dは、dのスコープ全体にわたって、dが発生するポイントで、スコープ内にあるnという名前の他の型の宣言をシャドウ化します。
nという名前のフィールドまたは仮パラメータの宣言dは、dのスコープ全体にわたって、dが発生するポイントでスコープ内にあるnという名前の他の変数の宣言をシャドウ化します。
nという名前のローカル変数または例外パラメータの宣言dは、dのスコープ全体にわたって、(a) dが発生するポイントでスコープ内にあるnという名前の他のフィールドの宣言、および(b) dが発生するポイントでスコープ内にあるが、dが宣言された最も内側のクラス内で宣言されていないnという名前の他の変数の宣言をシャドウ化します。
nという名前のメソッドの宣言dは、dのスコープ全体にわたって、dが発生するポイントでそれを囲むスコープ内にあるnという名前の他のメソッドの宣言をシャドウ化します。
パッケージ宣言によって他の宣言がシャドウ化されることはありません。
オンデマンド型インポート宣言によって他の宣言がシャドウ化されることはありません。
オンデマンド静的インポート宣言によって他の宣言がシャドウ化されることはありません。
単一モジュール・インポート宣言では他の宣言がシャドウ化されることはありません。
nという名前の型をインポートするパッケージpのコンパイル・ユニットc内の単一型インポート宣言dは、c全体にわたって、次の宣言をシャドウ化します。
pの別のコンパイル・ユニットで宣言されたnという名前の最上位型
cのオンデマンド型インポート宣言によってインポートされたnという名前の型
cのオンデマンド静的インポート宣言によってインポートされたnという名前の型
cの単一モジュール・インポート宣言によってインポートされたnという名前の型
nという名前のフィールドをインポートするパッケージpのコンパイル・ユニットc内の単一静的インポート宣言dは、c全体にわたって、cのオンデマンド静的インポート宣言によってインポートされたnという名前の静的フィールドの宣言をシャドウ化します。
シグネチャsを持つnという名前のメソッドをインポートするパッケージpのコンパイル・ユニットc内の単一静的インポート宣言dは、c全体にわたって、cのオンデマンド静的インポート宣言によってインポートされたシグネチャsを持つnという名前の静的メソッドの宣言をシャドウ化します。
nという名前の型をインポートするパッケージpのコンパイル・ユニットc内の単一静的インポート宣言dは、c全体にわたって、次の宣言をシャドウ化します。
cのオンデマンド静的インポート宣言によってインポートされたnという名前の静的型
cのオンデマンド型インポート宣言(7.5.2)によってインポートされたnという名前の型
cの単一モジュール・インポート宣言によってインポートされたnという名前の型。
この項の残りの部分に変更はありません。
6.5 名前の意味の確認
6.5.1 コンテキストに応じた名前の構文的分類
次のコンテキストでは、名前が構文的にModuleNameとして分類されます。
モジュール宣言内の
requires
ディレクティブ内(7.7.1)モジュール宣言内の
exports
またはopens
ディレクティブ内のto
の右側(7.7.2)単一モジュール・インポート宣言(7.5.5)の
module
の右側
次のコンテキストでは、名前が構文的にPackageNameとして分類されます。
モジュール宣言内の
exports
またはopens
の右側修飾されたPackageName内の「
.
」の左側
次のコンテキストでは、名前が構文的にTypeNameとして分類されます。
クラスまたはインタフェースを指定する場合:
モジュール宣言内の
uses
またはprovides
ディレクティブ内(7.7.1)単一型インポート宣言内(7.5.1)
単一静的インポート宣言内の
.
の左側(7.5.3)オンデマンド静的インポート宣言内の
.
の左側(7.5.4)コンストラクタ宣言内の
(
の左側(8.8)注釈内の
@
記号の後(9.7)クラス・リテラル内の
.class
の左側(15.8.2)修飾された
this
式の.this
の左側(15.8.4)修飾されたスーパークラス・フィールド・アクセス式の
.super
の左側(15.11.2)修飾されたメソッド呼出し式内の
.
Identifierまたは.super.
Identifierの左側(15.12)メソッド参照式内の
.super::
の左側(15.13)
型が使用されている17のコンテキスト内のReferenceType (配列型内のカッコの左側にあるReferenceType、パラメータ化された型内の<の左側、パラメータ化された型の非ワイルドカード型引数内、またはパラメータ化された型のワイルドカード型引数の
extends
またはsuper
句内を含む)を構成する識別子または点線付きの識別子シーケンスとして(4.11):インタフェース宣言の
extends
句内(9.1.3)汎用クラス、インタフェース、メソッドまたはコンストラクタの型パラメータ宣言の
extends
句内(8.1.2、9.1.2、8.4.4、8.8.4)メソッドのレシーバ・パラメータの型(8.4)
文(14.4.2、14.14.1、14.14.2、14.20.3)またはパターン(14.30.1)のローカル変数宣言内の型
例外パラメータ宣言内の型(14.20)
レコード・クラスのレコード・コンポーネント宣言の型 (8.10.1)
明示的なコンストラクタ呼出し文、クラス・インスタンス作成式、またはメソッド呼出し式に対する明示的な型引数リスト内(8.8.7.1、15.9、15.12)
非修飾クラス・インスタンス作成式内で、インスタンス化するクラス型として(15.9)、またはインスタンス化する無名クラスの直接スーパークラスまたは直接スーパーインタフェースとして(15.9.5)
配列作成式内の要素型(15.10.1)
キャスト式のキャスト演算子内の型(15.16)
instanceof
関係演算子に続く型(15.20.2)メンバー・メソッドを検索するための参照型として、またはコンストラクトに対するクラス型または配列型としてのメソッド参照式内(15.13)。
前述の17個のコンテキスト内のReferenceTypeの識別子からのTypeNameの抽出は、要素型や型引数などのReferenceTypeのサブ用語すべてに繰り返し適用することを意図しています。
たとえば、フィールド宣言に型
p.q.Foo[]
が使用されるとします。配列型のカッコは無視され、用語p.q.Foo
が識別子の点線シーケンスとして配列型内のカッコの左側に抽出され、TypeNameとして分類されます。後のステップで、p
、q
およびFoo
のどれが型名またはパッケージ名であるかが確認されます。別の例として、キャスト演算子に型
p.q.Foo<? extends String>
が使用されるとします。用語p.q.Foo
が識別子用語の点線シーケンスとして再度、今回はパラメータ化された型内の<
の左側に抽出され、TypeNameとして分類されます。用語String
が、パラメータ化された型のワイルドカード型引数のextends
句内の識別子として抽出され、TypeNameとして分類されます。
次のコンテキストでは名前がExpressionNameとして構文的に分類されています。
修飾されたスーパークラス・コンストラクタ呼び出し内で修飾する式として(8.8.7.1)
修飾されたクラス・インスタンス作成式内で修飾する式として(15.9)
配列アクセス式内で配列参照式として(15.10.3)
PostfixExpressionとして(15.14)
割当て演算子の左側のオペランドとして(15.26)
try
-with-resources文内のVariableAccessとして(14.20.3)
次のコンテキストでは、名前が構文的にMethodNameとして分類されます。
- メソッド呼出し式内の「
(
」の前(15.12)
次のコンテキストでは、名前が構文的にPackageOrTypeNameとして分類されます。
修飾されたTypeName内の「
.
」の左側オンデマンド型インポート宣言内(7.5.2)
次のコンテキストでは、名前が構文的にAmbiguousNameとして分類されます。
修飾されたExpressionName内の「
.
」の左側メソッド呼出し式内の「
(
」の前にある右端の.
の左側修飾されたAmbiguousName内の「
.
」の左側注釈要素宣言のデフォルト値句内(9.6.2)
要素と値のペア内の「
=
」の右側(9.7.1)メソッド参照式内の
::
の左側(15.13)
構文的分類の結果、特定の種類のエンティティを式の特定の部分に制限できるようになります。
フィールド、パラメータまたはローカル変数の名前を式として使用できます(15.14.1)。
メソッドの名前は、式内にメソッド呼出し式の一部としてのみ表示される場合があります(15.12)。
クラスまたはインタフェースの名前は、式内に、クラス・リテラルの一部(15.8.2)、修飾された
this
式(15.8.4)、クラス・インスタンス作成式(15.9)、配列作成式(15.10.1)、キャスト式(15.16)、instanceof
式(15.20.2)、enum定数(8.9)、あるいはフィールドまたはメソッドの修飾名の一部としてのみ出現できます。パッケージの名前は、式内にクラスまたはインタフェースの修飾名の一部としてのみ出現できます。
第7章: パッケージおよびモジュール
7.5 インポート宣言
インポート宣言を使用すると、名前付きクラス、インタフェースまたはstatic
メンバーを、単一の識別子で構成される単純名(6.2)で参照できます。
適切なインポート宣言がなしでは、別のパッケージで宣言されているクラスやインタフェースへの参照、または別のクラスやインタフェースのstatic
メンバーへの参照には、通常、完全修飾名(6.7)の使用が必要になります。
- ImportDeclaration:
- SingleTypeImportDeclaration
- TypeImportOnDemandDeclaration
- SingleStaticImportDeclaration
- StaticImportOnDemandDeclaration
- SingleModuleImportDeclaration
単一型インポート宣言(7.5.1)では、単一の名前付きクラスまたはインタフェースを、その正規名(6.7)を指定することによってインポートします。
オンデマンド型インポート宣言(7.5.2)では、パッケージ、クラスまたはインタフェースの正規名を指定することによって、名前付きパッケージ、クラスまたはインタフェースのアクセス可能なすべてのクラスとインタフェースを必要に応じてインポートします。
単一静的インポート宣言(7.5.3)では、正規名を指定することで、クラスまたはインタフェースから所定の名前を持つアクセス可能なすべての
static
メンバーをインポートします。オンデマンド静的インポート宣言(7.5.4)では、クラスまたはインタフェースの正規名を指定することで、名前付きクラスまたはインタフェースのアクセス可能なすべての
static
メンバーを必要に応じてインポートします。単一モジュール・インポート宣言(7.5.5)では、所定のモジュールでエクスポートされたパッケージのすべてのアクセス可能なクラスおよびインタフェースを必要に応じてインポートします。
これらの宣言によってインポートされるクラス、インタフェースまたはメンバーのスコープおよびシャドウ化については、6.3および6.4で規定されています。
import
宣言によって、実際にそのimport
宣言を含むコンパイル・ユニット内でのみ、クラス、インタフェースまたはメンバーを単純名で使用できるようになります。import
宣言によって導入されるクラス、インタフェースまたはメンバーのスコープには、同じパッケージ内の他のコンパイル・ユニット、現在のコンパイル・ユニット内の他のimport
宣言、または現在のコンパイル・ユニット内のpackage
宣言(package
宣言の注釈は除く)は本質的に含まれません。
7.5.5 単一モジュール・インポート宣言
単一モジュール・インポート宣言では、名前付きモジュールでエクスポートされたパッケージのすべてのpublic
の最上位クラスとインタフェースを必要に応じてインポートできます。
- SingleModuleImportDeclaration:
-
import
module
ModuleName;
単一モジュール・インポート宣言import module M;
は、次のパッケージ内のすべてのpublic
の最上位クラスとインタフェースを必要時にインポートします。
モジュール
M
により、現在のモジュールにエクスポートされたパッケージ。モジュール
M
の読取りのために現在のモジュールによって読み取られるモジュールでエクスポートされたパッケージ。これにより、プログラムは、別のモジュールからのクラスやインタフェースを参照するモジュールのAPIを使用できるようになります。このとき、該当する別のモジュールのすべてをインポートする必要はありません。
モジュールModuleNameが現在のモジュール(7.3)によって読み取られない場合は、コンパイル時にエラーが発生します。
現在のモジュールによって読み取られるモジュールは、
java.lang.module
パッケージ仕様(7.3)で説明されているように、解決の結果によって決まります。
同じコンパイル・ユニット内の複数の単一モジュール・インポート宣言は、同じモジュールを指名できます。これらの宣言は1つを除いてすべてが重複しているとみなされます。この結果、そのモジュールは1回のみインポートされたものとして扱われます。
単一モジュール・インポート宣言は、どのソース・ファイルでも使用できます。ソース・ファイルはモジュールの一部にする必要はありません。たとえば、モジュール
java.base
とjava.sql
は標準Javaランタイムの一部であるため、それ自体がモジュールとして開発されていないプログラムでインポートできます。パッケージをエクスポートしないモジュールのインポートが役立つ場合があります。これは、モジュールがパッケージをエクスポートする別のモジュールを間接的に必要とすることがあるためです。たとえば、
java.se
モジュールはパッケージをエクスポートしませんが、複数のモジュールを間接的に必要とするため、単一モジュール・インポート宣言import module java.se;
の効果は、これらのモジュールによってエクスポートされるパッケージ(再帰的にエクスポートされるパッケージなど)をインポートすることです。
例7.5.5-1.通常のコンパイル・ユニットの単一モジュール・インポート
モジュールを使用すると、パッケージのセットをグループ化して1つの名前で再利用できるようになります。また、モジュールのエクスポートされたパッケージは、統合された一貫性のあるAPIを形成することを目的としています。単一モジュール・インポート宣言を使用すると、開発者はモジュールによってエクスポートされたすべてのパッケージを1回でインポートできるため、モジュラ・ライブラリの再利用が容易になります。次に例を示します。
import module java.xml;
これにより、モジュールjava.xml
でエクスポートされたすべてのパッケージ内で宣言されているpublic
の最上位のクラスとインタフェースの単純名が、コンパイル・ユニットのクラスとインタフェースの宣言で使用できるようになります。したがって、単純名XPath
は、そのクラス宣言がシャドウ化または不明瞭化されていないコンパイル・ユニットのすべての場所で、モジュールjava.xml
でエクスポートされたパッケージjavax.xml.xpath
のインタフェースXPath
を参照します。
モジュールM0
に関連付けられている次のコンパイル・ユニットがあるとします:
package q;
import module M1; // What does this import?
class C { ... }
このモジュールM0
には、次の宣言があります:
module M0 { requires M1; }
単一モジュール・インポート宣言import module M1;
の意味は、M1
のエクスポートと、M1
が間接的に必要とするモジュールによって異なります。例として次について考えてみます:
module M1 {
exports p1;
exports p2 to M0;
exports p3 to M3;
requires transitive M4;
requires M5;
}
module M3 { ... }
module M4 { exports p10; }
module M5 { exports p11; }
単一モジュール・インポート宣言import module M1;
の効果は次のようになります:
public
の最上位のクラスとインタフェースをパッケージp1
からインポートします。これは、M1
がすべてに向けてp1
をエクスポートするためです。public
の最上位のクラスとインタフェースをパッケージp2
からインポートします。これは、M1
がp2
をコンパイル・ユニットが関連付けられているモジュールM0
にエクスポートするためです。さらにパッケージ
p10
からpublic
の最上位のクラスとインタフェースをインポートします。これは、M1
はp10
をエクスポートするM4
が間接的に必要になるためです。
コンパイル・ユニットによって、パッケージp3
またはp11
からインポートされるものはありません。
単一モジュール・インポート宣言は、パッケージ宣言のみが含まれているソース・ファイルに記述できます。そのようなファイルは、通常、package-info.java
と呼ばれ、パッケージ・レベルの注釈とドキュメント(7.4.1)の唯一のリポジトリとして使用されます。
例7.5.5-2.モジュラ・コンパイル・ユニットの単一モジュール・インポート
インポート宣言は、モジュラ・コンパイル・ユニットにも記述されます。次のモジュラ・コンパイル・ユニットは、単一モジュール・インポート宣言を使用して、モジュールjava.sql
に関連付けられたインタフェースDriver
の単純名をprovides
ディレクティブで使用できるようにします:
import module java.sql;
module com.myDB.core {
exports ...
requires transitive java.sql;
provides Driver with com.myDB.greatDriver;
}
モジュールM
を宣言するモジュラ・コンパイル・ユニットが、モジュールM
をインポートすることもできます。次の例では、クラスC
の単純名をuses
ディレクティブで使用できることを表しています:
import module M;
module M {
...
exports p;
...
uses C;
...
}
このモジュールM
によってエクスポートされたパッケージp
は、次のように宣言されています:
package p;
class C { ... }
単一モジュール・インポート宣言なしの場合は、uses
ディレクティブでクラスC
の修飾名を使用する必要があります。
次のようなモジュール宣言があるとします:
module M2 {
requires java.se;
exports p2;
...
}
このM2
によってエクスポートされるパッケージp2
は、次のように宣言されています:
package p2;
import module java.xml;
class MyClass {
...
}
モジュールM2
はモジュールjava.xml
に対する依存性を直接的に表していませんが、解決プロセスによってモジュールjava.xml
はモジュールM2
によって読み取られると判断されるため、モジュールjava.xml
のインポートは正しいままです。
例7.5.5-3.曖昧なインポート
複数のモジュールを明確にインポートすると、次のような名前の曖昧さが発生する可能性があります:
import module java.base;
import module java.desktop;
...
List l = ... // Error - Ambiguous name!
...
モジュールjava.base
は、public
List
インタフェースを持つパッケージjava.util
をエクスポートします。モジュールjava.desktop
は、public
List
クラスのパッケージjava.awt
をエクスポートします。両方のモジュールをインポートすると、単純名List
の使用は明らかに曖昧になり、コンパイル時にエラーが発生します。
ただし、単一のモジュールをインポートするだけでも、次のような名前の曖昧さが発生する可能性があります:
import module java.desktop;
...
Element e = ... // Error - Ambiguous name!
...
モジュールjava.desktop
は、public
Element
インタフェースとpublic
Element
クラスを持つパッケージのjavax.swing.text
とjavax.swing.text.html.parser
をそれぞれエクスポートします。そのため、単純名Element
の使用は曖昧になり、コンパイル時にエラーが発生します。
単一型インポート宣言は、名前の曖昧さを解決するために使用できます。単純名List
が曖昧な前の例は、次のように解決できます:
import module java.base;
import module java.desktop;
import java.util.List; // Resolving the ambiguity of the simple name List
...
List l = ... // Ok - List is resolved to java.util.List
...