対策する資格
Java Silver ・ 近日ORACLE Silver ・ 近日
Gold 保有者 監修1Z0-829 対応
モジュール(requires transitive)難易度 標準無料

3つのモジュールが次の module-info.java を持つ。

1   // ===== モジュール com.foo.util =====
2   module com.foo.util {
3       exports com.foo.util;            // public class Token を含む
4   }
5
6   // ===== モジュール com.foo.service =====
7   module com.foo.service {
8       requires transitive com.foo.util;
9       exports com.foo.service;         // Svc.make() は com.foo.util.Token を返す
10  }
11
12  // ===== モジュール com.foo.app =====
13  module com.foo.app {
14      requires com.foo.service;        // ← com.foo.util は requires していない
15  }

com.foo.app 内のコードが、次のように書かれている。正しい記述を選べ。

16  import com.foo.service.Svc;
17  import com.foo.util.Token;           // util を requires していないが…
18  Token t = Svc.make();
19  System.out.println(t.id());
  1. Acom.foo.appcom.foo.util.Token を参照できない。module-inforequires com.foo.util; を足さないとコンパイルエラー。
  2. Bcom.foo.servicerequires transitive com.foo.util によって暗黙的可読性(implied readability)が com.foo.app へ伝播するため、追加の requires なしで Token を参照でき、コンパイル・実行とも成功する。
  3. Ccom.foo.utilexports だけでなく com.foo.app 向けに opens しないと Token を参照できない。
  4. Drequires transitive は不正な構文であり com.foo.service のコンパイル時点でエラーになる。
正解・解説・誤答理由・ひっかけを見る▼ open
✓ 正解:BGold監修

解説

モジュールの requires は「読む(read)」関係を1段だけ作る。 通常 com.foo.appcom.foo.util の型を使うには、app 自身が requires com.foo.util する必要がある。

ところが requires transitive を付けると「自分を読むモジュールにも、その依存先を読ませる」という暗黙的可読性(implied readability)が成立する。

ここでは com.foo.servicerequires transitive com.foo.util しているので、 service を読む者(=app)は自動的に util も読める。よって app は requires com.foo.util を書かずとも Token を参照でき、コンパイル・実行とも成功する。

transitive は「公開APIの戻り値・引数に他モジュールの型が露出する」ときに使うのが定石(ここでは Svc.make()Token を返す)。これを付けないと、service を使う全モジュールが util を個別に requires する羽目になる。

各誤答が違う理由
  • Aこれは transitive が無い(=普通の requires com.foo.util)場合の挙動。transitive 付きでは追加の requires は不要。
  • Copens は実行時リフレクション用。コンパイル時の通常の型参照には無関係で、exports で足りている。
  • Drequires transitive は正規の構文(JLS / JPMS)。コンパイルは通る。
ひっかけ: 「使う型のモジュールは必ず自分で requires する」と機械的に覚えていると A を選ぶ。transitive は依存を“横流し”できる例外。逆に service が transitive を外すと、app は即コンパイルエラー(下記・実機確認の負側)。
実機確認の答え合わせ
javac --module-source-path ... --module com.foo.app → コンパイル成功
java --module com.foo.app/...Main → 出力:TKN

【負側の確認】service を「requires com.foo.util(transitive なし)」に変えて再ビルドすると app がコンパイル失敗:
Main.java:17: error: package com.foo.util does not exist
import com.foo.util.Token;
                   ^
Gold 保有者による書き下ろし解説・実機で検証済
この分野をもっと解いて、得点源に
モジュール を含む全問を分野別に演習できます(無料)。
演習する →