モジュール(exports vs opens)難易度 高無料
モジュール com.lib が次のように宣言されている(exports は無く opens のみ)。
1 module com.lib {
2 opens com.lib.model; // public class Entity を含む
3 }
別モジュール com.client(requires com.lib;)が、ソースコードで次のように com.lib.model.Entity を直接 import して使おうとする。結果は?
4 package com.client;
5 import com.lib.model.Entity;
6 public class Main {
7 public static void main(String[] a) {
8 System.out.println(new Entity().name());
9 }
10 }- Aコンパイル成功。
opensによりcom.clientはcom.lib.modelの public 型をコンパイル時に参照できる。 - Bコンパイルエラー。
opensは実行時のリフレクティブアクセスのみを許可し、コンパイル時/通常コードの型参照はexportsでなければ許可されない。 - Cコンパイルは成功するが、実行時に
IllegalAccessExceptionがスローされる。 - D
opensとexportsは同義であり、どちらを書いても結果は同じ。
正解・解説・誤答理由・ひっかけを見る▼ open
✓ 正解:B✓Gold監修
解説
exports と opens は「公開」の意味がまったく違う。1段ずつ整理する。
exports com.x = 他モジュールが com.x の public 型の public メンバを、コンパイル時も実行時も通常コードから使える。
opens com.x = 他モジュールが com.x に実行時の深いリフレクション(setAccessible(true) を含む。private にも届く)でアクセスできる。ただし通常のコンパイル時の型参照は許可しない。
opens はフレームワーク(Jackson の JSON マッピング、JPA、DI 等)が privateフィールドにリフレクションで触るために使うもの。
本問の com.client は import して new Entity() という通常のコンパイル時参照をしているので、opens しかない com.lib.model は「コンパイルからは見えない」。よってコンパイルエラー。
- A
opensはコンパイル時可視性を与えない。通常の import/newは通らない。 - Cそもそもコンパイルが通らないので、実行時例外に至らない。
- D同義ではない。
exports=通常アクセス(public のみ)、opens=実行時リフレクション(private 含む)。役割が直交する。
ひっかけ: 「
opens の方が private まで開くんだから、当然 public も使えるはず(exports の上位互換)」という直感。実際は軸が別で、コンパイル時参照は exports 専用。両方欲しければ両方書く(exports+opens)。実機確認の答え合わせ
opens のみの com.lib.model を client が import → javac がコンパイルエラー:
Main.java:5: error: package com.lib.model does not exist
import com.lib.model.Entity;
^
Main.java:8: error: cannot find symbol (class Entity)✓Gold 保有者による書き下ろし解説・実機で検証済