はじめに
Java SE11(Silver)で新たに試験項目に追加されたモジュールシステムについて、
基本事項をサンプルを交えて説明し、試験で必要そうなポイントを紹介していきたいと思います。
今回は初回ということで、ザックリとした説明と、
モジュールシステムが無い場合の問題点を説明します。
試験対策的にはコマンドの使い方あたりも知っておかないとダメそうでしたので、
次回以降、コマンドライン編とEclipse編に分けて投稿します。
1.モジュールシステムとは?
非常にザックリですが、以下になります。
複数のパッケージ(クラス)をまとめる仕組み。
公開・非公開や依存関係をより便利に管理することができる。
Java9で追加された。
2.それまでの問題点
モジュールシステムの採用のきっかけとなったであろう、問題点の1つを紹介します。
Java8まではアクセス修飾子による制御のみだったのですが、
それだと不都合が生じたためにモジュールシステムが追加された形です。
これをサンプルで説明していきます。
パッケージAに含まれるMyClientクラスが、実行用のクラスです。
このクラスはパッケージBのMyServiceクラスを参照しています。
パッケージCにはMyServiceで使うライブラリがまとめられているイメージで、
パッケージBには公開しますが、パッケージAには非公開としたいです。
これをアクセス修飾子のみでやるとしたら、以下対応となります。
【対応方法】
MyServiceクラス ⇒ publicにする
MyUtilクラス ⇒ publicにする
これで、MyServiceクラスはMyUtilクラスを参照でき、
MyClientクラスはMyServiceクラスを参照できるようになります。
ところが・・!
これでは構成図で非公開としている、MyClientからMyUtilの参照も可能となってしまいます。
つまり、モジュールシステム以前のアクセス制御が抱えていた問題は以下になります。
【問題点】
あるパッケージ内のクラスを外部に公開する際に、その公開範囲の設定ができない!
もちろんこの他にも問題点や、モジュールシステムの利点があったために採用されたわけですが、
Silverの知識でもわかりやすいかと思い、このケースを紹介しています。
3.サンプルで確認
では今回は次回以降の準備として、上記の構成図に基づいたサンプルを作成してみます。
なお、この記事ではeclipseを使用しています。
①MyUtilクラスを作成
構成図で言うところの「パッケージC」と「MyUtilクラス」を作成します。
手順は以下です。
【手順】
1.「myutil」プロジェクトを作成(※module-info.javaは作成しない)
2.「jp.ssie.ocjp.util」パッケージを作成
3.「MyUtil」クラスを作成
4. jarファイルを作成
そして、MyUtilクラスには以下を記述します。
package jp.ssie.ocjp.util; public class MyUtil { // 税率 private static final double RATE = 1.1; // 税込み金額を計算するメソッド public static int calcTax(int price) { return (int) (price * RATE); } }
税込み金額を計算する、calcTaxメソッドを公開しています。
一旦、MyUtilクラスはこれで完成です。
次にコンパイルとjarファイルのエクスポートを行いますが、
今回は簡単のためにeclipseのGUI操作で作成します。
エクスポート用のフォルダとして、「jar」フォルダをワークスペース直下にでも作りましょう。
↓ 私の場合
C:\202003java\pleiades\workspace\jar
プロジェクトを右クリックして「エクスポート」をクリックしてください。
エクスポート先を、作成した「jar」フォルダ配下とし、ファイル名を「util.jar」とします。
↓ 私の場合
C:\202003java\pleiades\workspace\jar\util.jar
設定できたら「完了」をクリックして、jarファイルが作成されていることを確認してください。
これで、MyUtilクラス関連の準備は一旦完成です。
②MyServiceクラスを作成
構成図で言うところの「パッケージB」と「MyServiceクラス」を作成します。
手順は以下です。
【手順】
1.「myservice」プロジェクトを作成(※module-info.javaは作成しない)
2.「lib」フォルダを作成して、「util.jar」をコピーして配置
3. クラスパスに「util.jar」を追加
4.「jp.ssie.ocjp.service」パッケージを作成
5.「MyService」クラスを作成
6. jarファイルを作成
MyUtilの場合と比べて大きく異なるところだけを赤字にしています。
まず手順2までのところで、以下となります。
クラスパスへの追加も今回はGUIで、以下の手順で行います。
プロジェクト右クリック
→ ビルド・パス
→ ビルド・パスの構成
→ クラスパス
→ 外部JARの追加
あとはMyUtilと同様なので、必要な情報のみ記載します。
MyServiceクラスの中身が以下です。
package jp.ssie.ocjp.service; import jp.ssie.ocjp.util.MyUtil; public class MyService { // 買い物する商品の合計金額(税込み)を表示するメソッド public static void showTotalPrice(int[] prices) { // 合計金額用の変数 int result = 0; // 商品ごとに税込み金額を計算して加算 for (int price : prices) { result += MyUtil.calcTax(price); } // 結果表示 System.out.println(result); } }
Jarファイルは、「jar」フォルダに「service.jar」として保存します。
↓ 私の場合
C:\202003java\pleiades\workspace\jar\service.jar
jarファイルが作成できていればOKです。
③MyClientクラスを作成
最後に構成図で言うところの「パッケージA」と「MyClientクラス」を作成します。
手順は以下です。
【手順】
1.「myclient」プロジェクトを作成(※module-info.javaは作成しない)
2.「lib」フォルダを作成して、「util.jar」「service.jar」をコピーして配置
3. クラスパスに「util.jar」「service.jar」を追加
4.「jp.ssie.ocjp.client」パッケージを作成
5.「MyClient」クラスを作成
6. 実行
こちらも異なるところだけ赤字にしています。
MyClientクラスの実装は以下です。
package jp.ssie.ocjp.client; import jp.ssie.ocjp.service.MyService; import jp.ssie.ocjp.util.MyUtil; public class MyClient { public static void main(String[] args) { // これがやりたいこと int[] prices = { 100, 200, 300 }; MyService.showTotalPrice(prices); // これができてしまうのがマズい System.out.println(MyUtil.calcTax(1000)); } }
こちらはjarクラスは作成しない代わりに、実行して以下の表示となればOKです。
確認ポイント
これで一旦、クラス構成図に基づいたサンプルは完成です。
注目したいのはMyClientの15行目で、MyUtilクラスを参照できてしまっている点です。
アクセス修飾子では制限ができていないですね!(publicなので当然ですよね・・・)
これでは困るので、モジュールシステムを使って非公開にしよう!
というのが、次回以降のお話になります。
まとめ
今回は概要と準備になるので、以上となります。
まずはモジュールシステム以前(パッケージのみ)の場合の1つの問題点として、
アクセス制限の問題があったということを知った上で、次回以降の記事を見て頂ければと思います。