在〈淺談 Java 模組平臺系統〉中,談到了如何建立、編譯、運行簡單的模組,在模組描述檔的設定中,知道模組必須 exports
套件,另一個模組在 requires
了該模組之後,才能使用那個套件中的類別,你認識了模組路徑,也知道了在類別路徑下被發現的類別,都會被自動歸類到未具名模組,在模組路徑下被發現的類別,則都屬於某個具名模組,如果應用程式採取模組化設計,預設就會依賴在 java.base
模組之上, java.base
模組 exports
了它全部的套件,任何模組都可以讀取 java.base
模組。
在 JDK8 或舊版本中,public
表示各套件間,也就是整個應用程式都可以存取,然而,在 JDK9 之後多了模組,模組中的 public
類別、方法、值域是否能被另一模組看見,還要視模組設定而定。
在定義模組時必須記得,同一個套件不可以同時出現在被 requires
的兩個模組中,這稱為分裂套件(Split package)會導致編譯失敗,而執行時期會產生 LayerInstantiationException
。
就算是 Java SE API,若不是 java.base
模組中的類別,還是必須 requires
相關的模組,例如,要使用內建日誌 API 的話,必須 requires java.logging
,想使用 JDBC API 的話,必須 requires java.sql
。
許多程式庫都還沒有模組化,那麼該怎麼使用這個 JAR 檔案呢?暫時放在類別路徑上的話,會成為未具名模組,因為未具名模組沒有名稱,如果你的應用程式採取模組化設計,就沒有辦法在模組描述檔中 requires
了,這時候程式碼想使用類別路徑上的 API 就會發生編譯錯誤了。
不過,如果程式碼中不會依賴在到任何 JAR 檔案的 API,例如 JDBC 驅動程式類別是採用反射(Reflection)來載入,之後透過 JDBC 標準 API 來撰寫程式,因此將驅動程式的 JAR 放在類別路徑上,就算採取模組化設計,只要 requires java.sql
,之後就可以使用 JDBC 載入驅動程式進行資料庫連線。
你也許只是想讓既有的應用程式跑在 JDK9 上,不打算模組化,也就是從程式進入點開始的每個類別,都是基於類別路徑,也就是都在未具名模組之中,然而要注意的是,對於其他同樣是放在類別路徑上的 JAR,在 API 的使用上也許沒有問題,使用的是 java.sql
、java.util.logging
套件中的 API 也 OK,然而若使用到 javax.xml.bind.*
、javax.rmi
等套件,還是會出現編譯錯誤。
這是因為這些套件雖然包含在 Java SE 中,然而實際上是與 Java EE 相關的 API,在 JDK9 中還是有這些套件,不過被劃分到 java.se.ee
模組,JVM 預設並不會載入這個模組,因此編譯與執行時,必須使用 --add-modules java.se.ee
,才找得到這些套件。