概要
Javaのモジュールシステムについて、概念的なイメージと実際のコード例で理解を深めるための記事です。
読者はJava Silverの資格勉強中の方やJava入門者を想定しています。
内容は以下のようになっています。
・基本的なモジュール参照
・推移的なモジュール参照
・限定的なモジュール参照
環境
・Eclipse
・Java11
モジュールシステム概要
Java9から導入された仕組みです。
これによりパッケージ単位で公開/非公開を設定できるようになりました。
Java8以前まではパッケージ単位で設定できなかったので、publicなクラスにしてしまうとどのパッケージからでもアクセスできてしまうという課題がありました。
モジュールシステムが導入されたことで、特定のパッケージからのみアクセス可能にすることもできるようになり、パッケージ単位での情報隠蔽が実現されました。
全体像
本記事で解説するパッケージ構成の全体像です。
後続で個々のケースについて詳解していきますので、ここではまず4つのモジュールがあること、またそれぞれがどのモジュールを参照しようとしているかについてイメージを持っていてください。
基本的なモジュール参照
基本的なモジュール参照のケースです。
ここではmoduleAがexpパッケージを公開し、selfがmoduleAを参照しています。
moduleAの構成
- module-info.java
123module moduleA {exports exp;}
- Hello.java
12345678package exp;public class Hello {public static void hello(){System.out.println("hello() of Hello class in exp package at moduleA.");}}
selfの構成
- module-info.java
123module self {requires moduleA;}
- Hello.java
12345678package self;public class Hello {public static void hello(){System.out.println("hello() of Hello class in self package.");}}
- SelfMain.java
12345678package self;public class SelfMain {public static void main(String[] args) {Hello.hello();exp.Hello.hello();}}
- ビルドパス
moduleAをビルドパスに追加します。
実行結果
1 2 |
hello() of Hello class in self package. hello() of Hello class in exp package at moduleA. |
推移的なモジュール参照
推移的なモジュール参照のケースです。
ここではmoduleCがexp2パッケージを公開し、moduleAが参照時にtransitive指定することで、moduleAを参照するモジュールにもmodeulCが参照できるように宣言しています。
そのため、selfはmoduleAを参照することでmoduleCを利用することができるようになります。
moduleCの構成
- module-info.java
123module moduleC {exports exp2;}
- Hello.java
12345678package exp2;public class Hello {public static void hello(){System.out.println("hello() of Hello class in exp package at moduleC.");}}
moduleAの構成
変更なし
- module-info.java
1234module moduleA {exports exp;requires transitive moduleC; // ← 追記}
- Hello.java
変更なし
selfの構成
変更なし
- module-info.java
変更なし - Hello.java
変更なし - SelfMain.java
123456789package self;public class SelfMain {public static void main(String[] args) {Hello.hello();exp.Hello.hello();exp2.Hello.hello(); // ← 追記}}
- ビルドパス
moduleCをビルドパスに追加します。
実行結果
1 2 3 |
hello() of Hello class in self package. hello() of Hello class in exp package at moduleA. hello() of Hello class in exp package at moduleC. |
限定的なモジュール参照
限定的なモジュール参照のケースです。
ここではmoduleBがexp3パッケージをmoduleAに対してのみ公開しています。
そのため、moduleA以外(self)からはmoduleBを利用することができないようになっています。
moduleBの構成
- module-info.java
123module moduleB {exports exp3 to moduleA;}
- Hello.java
12345678package exp3;public class Hello {public static void hello(){System.out.println("hello() of Hello class in exp package at moduleB.");}}
moduleAの構成
変更なし
- module-info.java
12345module moduleA {exports exp;requires transitive moduleC;requires moduleB; // ← 追記}
- Hello.java
変更なし
selfの構成
変更なし
- module-info.java
1234module self {requires moduleA;requires moduleB; // ← 追記}
- Hello.java
変更なし - SelfMain.java
12345678910package self;public class SelfMain {public static void main(String[] args) {Hello.hello();exp.Hello.hello();exp2.Hello.hello();exp3.Hello.hello(); // ← 追記}}
- ビルドパス
moduleBをビルドパスに追加します。
実行結果
1 2 3 4 |
Exception in thread "main" java.lang.Error: Unresolved compilation problem: The type exp3.Hello is not accessible // ← 利用不可 at self/self.SelfMain.main(SelfMain.java:8) |
まとめ
- モジュールシステムとは端的に言うと、パッケージ単位で情報隠蔽を実現する仕組みである。
- 基本的なモジュール参照は、exportsでパッケージを公開し、requiresで参照先を指定する。
- 推移的なモジュール参照は、requires transitive指定することで自身が参照する他のモジュールを自身を参照している他のモジュールにも公開することができる。
- 限定的なモジュール参照は、指定したモジュールのみに対して公開することができる。
参考
本記事のモジュール構成は以下の記事を参考にさせて頂きました。
Javaのモジュールシステム入門
コメント