Question 1
The directory `mods` holds three compiled modules. Two of them contain the **same** package, `com.shared`: ```java module com.first { exports com.shared; } // contains com.shared.Alpha module com.second { exports com.shared; } // contains com.shared.Beta module com.app { requires com.first; // note: com.second is NOT required } package com.app; import com.shared.Alpha; public class Main { public static void main(String[] args) { System.out.println(Alpha.who()); // Alpha.who() returns "alpha from com.first" } } ``` All three modules were compiled successfully, com.app with `--module-path mods`. You now run: ``` java --module-path mods -m com.app/com.app.Main ``` What happens?
A. It prints `alpha from com.first` — com.second is observable but is never resolved, so the module graph that gets built contains no split package.Correct answer
Correct: com.app requires only com.first, so com.second is observable but never resolved and never joins the module graph. The built graph therefore contains no split package and the program prints alpha from com.first.
B. It fails at run time with `NoClassDefFoundError: com/shared/Alpha`, because the duplicate package makes `com.shared` ambiguous to the class loader.
Wrong: this imagines the duplicate package is detected lazily at class load. Split packages are checked eagerly when the layer is constructed, and here there is no conflict at all because com.second is never resolved.
C. It fails at startup with `LayerInstantiationException: Package com.shared in both module com.first and module com.second` — a split package anywhere on the module path is fatal.
Wrong: this names the right exception for the wrong trigger. LayerInstantiationException only fires if com.second is actually resolved (for example via --add-modules); merely sitting on the module path is not enough.
D. It prints `beta from com.second`, because when two modules on the module path contain the same package the one found later wins.
Wrong: this invents a last-one-wins rule. JPMS has no such precedence; a genuine split-package conflict is an error, never a silent pick, and here com.second is never even resolved.
Explanation
The split-package rule is a constraint on the **module graph**, not on the module path. It says: no two modules *in the same layer* may contain the same package. Modules only enter that layer if they are **resolved**, and resolution starts from the root — here `com.app`, named by `-m` — and follows `requires` edges. com.app requires only com.first, so the resolved graph is `{com.app, com.first, java.base}`. com.second is *observable* (it sits on the module path, ready to be found) but nothing pulls it in, so it never joins the graph, and there is no conflict to report. The program runs and prints `alpha from com.first`. Why the others are wrong: `It fails at startup with `LayerInstantiationException`...` names the right exception for the wrong trigger — this is the single most instructive distractor here. That exception is exactly what you get **if com.second is resolved**: `java --module-path mods --add-modules com.second -m com.app/com.app.Main` dies before `main` with `Error occurred during initialization of boot layer` / a `java.lang.LayerInstantiationException` reporting `Package com.shared in both module ...` (the JVM names the two modules in an unspecified order). Merely *sitting on the module path* is not enough. `It prints `beta from com.second`...` invents a last-one-wins rule. There is no such precedence in JPMS; a genuine conflict is an error, never a silent pick. `It fails at run time with `NoClassDefFoundError`...` imagines the conflict is detected lazily, at class load. Split packages are checked eagerly, when the layer is constructed, precisely so that this class of ambiguity can never reach a class loader. Exam tip: hold *observable* and *resolved* apart — it is the distinction this whole question turns on, and it is the same one that makes `requires static` fail at run time. Also note the compile-time face of the rule: had com.app declared `requires com.second;` as well, javac would have refused it up front with `error: module com.app reads package com.shared from both com.first and com.second`.