モジュールとは、パッケージを束ねるための単位です。Java 9で追加されました。 モジュールを利用することで、配下のパッケージに対するアクセス権限をより細かに設定できるようになります。具体的には、
- 現在のモジュールの中でだけpublic
- 特定のモジュールに対してだけpublic
- すべてのモジュールに対してpublic
なパッケージを設定できます。たとえばライブラリをモジュールで束ねることで、そのライブラリの中でだけ利用しているパッケージが、不用意に他のコードからアクセスされることがなくなります(*)。
*)従来のJavaでは、ライブラリ内部でのみ利用するパッケージを不可視にする手段はありませんでした。パッケージプライベートよりも緩い権限が、すぐさま「すべてに対してpublic」だったからです。
標準ライブラリもモジュール
Java 9以降では、標準ライブラリもすべてモジュール化されています。具体的には、コマンドラインから以下のコマンドで確認できます。
> cd C:\jdk-23.0.1\bin
> java --list-modules
java.base@23.0.1
java.compiler@23.0.1
java.datatransfer@23.0.1
java.desktop@23.0.1
java.instrument@23.0.1
java.logging@23.0.1
java.management@23.0.1
java.management.rmi@23.0.1
java.naming@23.0.1
java.net.http@23.0.1
...中略...
jdk.naming.rmi@23.0.1
jdk.net@23.0.1
jdk.nio.mapmode@23.0.1
jdk.sctp@23.0.1
jdk.security.auth@23.0.1
jdk.security.jgss@23.0.1
jdk.unsupported@23.0.1
jdk.unsupported.desktop@23.0.1
jdk.xml.dom@23.0.1
jdk.zipfs@23.0.1
それぞれのパッケージ(クラス)が属するモジュールは、APIリファレンスからも確認できます。

モジュールの基本
モジュールを定義するには、ソースフォルダーのトップにモジュール定義ファイル(module-info.java)を配置するだけです。
module-info.java
- module mynavi {
- }
これでmynaviモジュールを定義したことになります(Eclipseでプロジェクトを作成した場合には、[module-info.javaファイルの作成]にチェックを入れると作成されます)。初期の状態では、{…}の中身は空ですが、最低限モジュールを定義するだけであればこれで十分です。この後、「依存するモジュール」「外部に公開するパッケージ」などを設定する際には、{…}配下にコードを記述していくことになります。
他のモジュールを利用する – requires宣言
モジュールの世界では、デフォルトでは異なるモジュールにはアクセスできません。別のモジュールを利用したい場合には、モジュール定義ファイルにrequires宣言を追加してください。たとえば以下は、java.net.httpモジュールを利用する例です(java.net.httpモジュールには、HttpClientなどHTTP通信に関わるクラスが定義されています)。
module-info.java
- module mynavi {
- requires java.net.http;
- }
requires宣言なしにjava.net.httpモジュールにアクセスした場合、「The type java.net.http.HttpClient is not accessible」のようなエラーとなります。
基本的なコードでrequires宣言を意識しなくてもよかったのは、標準ライブラリのjava.lang、java.ioなど主だったパッケージがjava.baseというモジュールに登録されているからです。java.baseモジュールはrequires宣言なしで無条件にアクセスできるというルールがあります。
推移的な依存関係を宣言する – requires transitive宣言
ただし、モジュールが利用しているモジュールをすべて列挙するのは、中々に厄介です。たとえば、モジュールが利用している先のモジュールで利用しているモジュール(=推移的な依存)をすべて把握するのは大概難しいはずです。
しかし、requires transitive宣言では、そうした推移的な依存を表現できます。たとえば、以下のような例です。
- module mod1 {
- requires mod2;
- }
- -----------------------------------------------------------------------------
- module mod2 {
- requires transitive java.net.http;
- requires transitive java.sql;
- }
この場合、mod1モジュールはmod2モジュール経由でjava.net.http/java.sqlモジュールに依存していますが、mod1側でこれらのモジュールをrequires宣言する必要はありません。これが推移的な依存関係を宣言する、という意味です(よって、太字を削除した場合、mod1モジュールはjava.net.http/java.sqlモジュールを明示的にrequires宣言しなければなりません)。
配下のパッケージを公開する – exports宣言
モジュール配下のパッケージは、デフォルトでモジュールプライベート(=モジュールの外からはアクセスできない)と見なされます。モジュールの外からパッケージへのアクセスを許可するには、exportsで公開したいパッケージを宣言してください。
たとえば以下はmynaviモジュールからcom.example.mynavi.basicパッケージを公開する例です。
- module mynavi {
- exports com.example.mynavi.basic;
- }
特定のモジュールに対してのみパッケージを公開したいならば、exports…to宣言を利用します。たとえば、以下はhoge/piyoモジュールに対してのみcom.example.mynavi.basicパッケージを公開する例です。
- module mynavi {
- exports com.example.mynavi.basic to hoge, piyo;
- }
自動モジュール
モジュールはJava 9で導入されたしくみです。よって、アプリによっては非モジュールなコードとモジュール前提のコードとが混在しているかもしれません。このような状態でも、非モジュールをモジュールとして扱えるようにするためのしくみが、自動モジュールです。
具体的には、モジュールパスに配置された.jarファイルで、モジュール定義ファイルを持たないコードは、自動モジュールと見なされます。
モジュールパスとは、モジュールの検索先を表すパスのことです。Eclipseであれば、プロジェクトのプロパティから[Javaのビルド・パス]-[ライブラリー]タブから確認できます。

自動モジュールの名前は、以下のルールで決定します。
- .jarファイルの名前から拡張子とバージョン番号を除去した上で、非英数字をハイフンで置き換えたもの(hoge-piyo-1.0.1.jarならばhoge.piyoがモジュール名)
- META-INF/MANIFEST.MFのAutomatic-Module-Name属性で宣言された名前(Automatic-Module-Name: hoge.piyo)
自動モジュールはあくまで便宜的なモジュールなので、
- 配下のすべてのパッケージを公開(exports)
- モジュールパスに登録されたすべてのモジュールをrequires
したのと同じように動作します。
- オブジェクト指向構文_目次
- class命令
- new演算子
- フィールドを定義する
- static final修飾子
- メソッドを定義する
- コンストラクターを定義する
- レコード
- package宣言
- import命令
- import static命令
- ネストしたクラスを定義する
- モジュール
監修