Java モジュール

最終更新: 2026-02-19 04:54:04 +0800 +0800
tags: Java | Jpms | Modules
原文は英語で書かれています。あなたはAI翻訳版を読んでいます。

Java Platform Module System (JPMS) は、依存関係とパッケージのカプセル化を明示的にします。名前付きモジュールには記述子 module-info.java がソースルートに含まれます。コンパイルすると、展開されたモジュールディレクトリまたはモジュール化された JAR に module-info.class が生成されます。

java
module com.example.app {
    requires com.example.codec;
    uses com.example.codec.Decoder;
}

module com.example.codec {
    exports com.example.codec.api;
    exports com.example.codec.internal to com.example.app;
    opens com.example.codec.model to com.example.json;
    provides com.example.codec.Decoder with com.example.codec.JsonDecoder;
}

コンパイル、パッケージ化、起動 #

従来のマルチモジュールソースツリーでは、モジュールソースパス以下にモジュールごとのディレクトリを置きます。次のようにコンパイルします。

sh
javac --module-source-path src -d out -m com.example.app,com.example.codec
jar --create --file app.jar --main-class com.example.app.Main -C out/com.example.app .
java --module-path libs:app.jar --module com.example.app

jar --main-class は実行可能なメインクラスを記録しますが、起動時に java -m module/name.Main で 1 つを指定できるため任意です。jlink はモジュールの推移閉包からランタイムイメージを作成します。モジュールパス上のモジュール化された JAR と JMOD を受け入れますが、JMOD はランタイム成果物ではありません。

sh
jlink --module-path "$JAVA_HOME/jmods:libs" \
      --add-modules com.example.app --output image
image/bin/java -m com.example.app

可読性とカプセル化 #

requires はモジュールを可読にします。requires transitive はその可読性を依存モジュールへ再エクスポートし、requires static はコンパイル時には必須ですが実行時には任意です。exports は、すべての可読モジュールに対して、または to を使った名前付きリストに対して、パッケージ内の public 型へのコンパイル時および通常の実行時アクセスを許可します。opens は通常の型アクセスを許可せずに深いリフレクションを許可し、open module はすべてのパッケージを開きます。フレームワーク統合には限定的な opens を優先してください。

uses と provides ... with ... はモジュール記述子内でサービスを宣言します。ServiceLoader はモジュール解決中にこれらの宣言を使用します。パッケージはモジュールから独立したアクセス単位ではないため、public であるだけではエクスポートされていないパッケージを迂回できません。

解決と移行 #

各フェーズでは、モジュールパスとシステムモジュールおよびアップグレードモジュールが、観測可能なモジュールの集合を形成します。解決はルートモジュールから始まり、requires エッジをたどります。同じ名前のモジュールが重複すると、クラスパスの順序で選択されるのではなく失敗します。名前付きモジュールには分割パッケージを含められません。解決された 2 つの名前付きモジュールに同じパッケージがあるとエラーになります。この規則によって、パッケージの所有権とカプセル化が決定論的になります。

クラスパスのコードは名前のないモジュールに属します。解決された名前付きモジュールのエクスポートされたパッケージを読み取り、そのパッケージはエクスポートおよびオープンされていますが、名前付きモジュールは名前のないモジュールに対する requires を宣言できません。モジュール化されていない JAR はモジュールパス上では自動モジュールになります。派生名またはマニフェスト名を持ち、解決されたすべてのモジュールを読み、すべてのパッケージをエクスポートおよびオープンします。自動モジュールは段階的な移行に役立ちますが、意味のあるカプセル化は提供しません。モジュール境界に依存する前に、明示的な記述子に置き換えてください。

名前付きモジュールの境界を越えるリフレクションには、通常のアクセス可能性に加えて、深いアクセスのためにオープンなパッケージが必要です。--add-exports と --add-opens は移行またはデプロイ時のオーバーライドであり、モジュールが所有する記述子の代替ではありません。

参照 #

コメント

GitHub で閲覧・コメントする(投稿にはログインが必要です)