找不到任何結果

您的搜尋未與任何結果相符。

以下操作有助您找到所需內容,建議您不妨一試:

  • 檢查您關鍵字搜尋的拼字是否正確。
  • 改用您所輸入關鍵字的同義詞,例如以「應用軟體」取代「軟體」。“”“”
  • 嘗試下列其中一項熱門搜尋。
  • 開始新的搜尋。
常見問題

 

Java 9 | 摘錄

瞭解 Java 9 模組

它們是什麼以及如何使用它們

作者:Paul Deitel


Paul Deitel

Paul Deitel

在本文中,我將介紹 Java 9 Platform Module System (JPMS),這是自 Java 誕生以來非常重要的新軟體工程技術。模組化是 Project Jigsaw 的成果,可協助所有層級的開發人員在建置、維護和發展軟體系統 (尤其是大型系統) 時提高工作效率。

什麼是模組?

模組化在套裝程式之上添加較高的聚總層級。關鍵的新語言元素是模組,它是一組專屬命名、可重用的相關套裝程式、資源 (例如圖像和 XML 檔案) 和模組描述符,用於指定:

  • 模組名稱
  • 模組相依性 (亦即此模組相依的其他模組)
  • 明確提供給其他模組使用的套裝程式 (其他模組隱式不可用模組中的所有其他套裝程式)
  • 其提供的服務
  • 其使用的服務
  • 允許哪些其他模組使用 reflection

歷史

Java SE 平台自 1995 年誕生以來,目前約獲 1 千萬名開發人員用來為物聯網 (IoT) 和其他嵌入式裝置等受資源限制的裝置建置各種小型應用程式,到大規模業務關鍵型和任務關鍵型系統。市面上有大量的舊有代碼,但到目前為止,Java 平台主要是單一的通用解決方案。多年來,人們針對模組化 Java 做出了各種努力,但沒有一個被廣泛應用,也沒有一個可以用於模組化 Java 平台。

實現 Java SE 平台的模組化充滿挑戰性,並且投入了大量的時間。JSR 277:Java Module System 最初於 2005 年針對 Java 7 推出,之後被 JSR 376:Java Platform Module System 取代,作為 Java 8 的目標,直到 Java 9 延遲到 2017 年 9 月推出之後,Java SE 平台在 Java 9 中進行了模組化。

目標

每個模組都必須明確指出其相依性。

根據 JSR 376,對 Java SE 平台進行模組化的主要目標是:

  • 可靠的配置 — 模組提供了在編譯期和執行期加以識別模組之間相依性的機制,系統可以透過這些相依性確保所有模組的子集合能夠滿足應用程式的需求。
  • 強封裝 — 模組中的套裝程式只有在模組明確匯出時可供其他模組存取,即使如此,其他模組也無法使用這些套裝程式,除非明確指出其需要其他模組的功能。由於潛在攻擊者只可以存取較少的類別,因此提高了平台的安全性。您會發現,模組化可幫助您建立更簡潔、更符合邏輯的設計。
  • 可擴展的 Java 平台 — 在這之前,Java 平台是由大量的套裝程式組成,因此難以開發、維護和發展,而且還不能輕易地被子集化。現在,此平台被模組化為 95 個模組 (此數字可能隨著 Java 的發展而變化),您可以建立僅包含應用程式或目標裝置所需的模組的自訂執行時期。例如,如果裝置不支援 GUI,您可以建立不包含 GUI 模組的執行時期,從而大幅減少執行時期的大小。
  • 更佳的平台完整性 — 在 Java 9 之前,您可以使用平台中許多不預期供應用程式使用的類別,透過強封裝,這些內部 API 確實被封裝並隱藏在使用該平台的應用程式中。如果您的程式碼相依於內部 API,那麼將舊有程式碼移轉至模組化 Java 9 可能會出現問題。
  • 提高效能 — JVM 使用各種最佳化技術來提高應用程式效能。JSR 376 表明,當事先知道某些技術僅在特定模組中被使用,這些技術會更有效。

JDK 模組清單

JEP 200:THE MODULAR JDK

JEP 201:MODULAR SOURCE CODE

JEP 220:MODULAR RUN-TIME IMAGES

JEP 260:ENCAPSULATE MOST INTERNAL APIS

JEP 261:MODULE SYSTEM

JEP 275:MODULAR JAVA APPLICATION PACKAGING

JEP 282: JLINK:THE JAVA LINKER

JSR 376:JAVA PLATFORM MODULE SYSTEM

JSR 379:JAVA SE 9

表 1.Java 模組化 JEP 和 JSR

Java 9 的關鍵概念是將 JDK 分成支援各種組態的模組。(參閱「 JEP 200:The Modular JDK」。表 1 顯示了與 Java 模組化有關的所有 JEP 和 JSR。)使用 JDK bin 資料夾中的 java 命令配搭 --list-modules 選項,如下所示:

java -- list-modules

列出 JDK 的模組集,其中包括實行 Java 語言 SE 規格 (以 java 為開頭的名稱)、JavaFX 模組 (以 javafx 為開頭的名稱)、JDK 特定模組 (以 jdk 為開頭的名稱) 以及 Oracle 特定模組 (以 oracle 為開頭的名稱)。每個模組名稱後面跟著一個版本字串 — @9 表示該模組屬於 Java 9。

模組宣告

如上所述,模組必須提供模組描述元,指定模組的相依性、模組提供給其他模組使用的套裝程式等等。模組描述元是模組宣告的編譯版本,定義在名為 module-info.java 的檔案中。每個模組宣告都是以關鍵字 module 開頭,後面跟著唯一的模組名稱和以大括號括住的模組主體,如下所示:

模組系統的關鍵動機是強封裝。

module modulename
}

模組宣告的主體可以是空的,也可以包含各種模組指令,包括 requiresexportsprovides…withusesopens (我們討論的每個指令)。如稍後所見,編譯模組宣告會建立模組描述區,該描述區儲存在模組根資料夾中名為 module-info.class 的檔案中。在這裡,我們簡要介紹每個模組指令。之後,我們將呈現實際的模組宣告。

關鍵字 exportsmoduleopenopensprovidesrequiresuseswith 以及我們稍後介紹的 totransitive 都是受限的關鍵字。這些僅是模組宣告中的關鍵字,並且可以在程式碼中的其他任何地方用作識別碼。

requires。requires 模組指令指定此模組相依於其他模組 ,此關係稱為模組相依性。每個模組都必須明確聲明其相依性。當模組 A requires 模組 B 時,稱為模組 A 讀取模組 B,模組 B 被模組 A 讀取。若要指定其他模組的相依性,請使用 requires,如下所示:

requires modulename;

另外還有一個 requires static 指令,用來指示在編譯時是必需的,但在程式實際執行時是可選的。這稱為選擇性相依項,但不會在本介紹中討論。

requires transitive — 隱式可讀性。若要指定其他模組的相依性,並確保其他模組讀取您的模組時也會讀取隱式可讀性,請使用 requires transitive (如下所示):

requires transitive modulename;

請考慮 java.desktop 模組宣告中的下列指令:

requires transitive java.xml

在此情況下,任何讀取 java.desktop 的模組也會隱式讀取 java.xml。例如,如果 java.desktop 模組中的方法傳回模組中的類型 java.xml,則讀取的模組中的程式碼 java.desktop 將變得依賴 java.xml。如果 java.desktop 模組宣告中沒有 requires transitive 指令,除非這些相關模組顯式讀取 java.xml,否則這些模組將不會編譯。

根據 JSR 379,Java SE 的標準模組在任何情況下都必須具備隱含的可讀性,如此處所述。此外,雖然 Java SE 標準模組可能依賴非標準模組,但不得將隱含的可讀性授予這些模組。這確保了僅依賴 Java SE 標準模組的程式碼可以跨 Java SE 導入移植。

exports 及 exports…to。exports 模組指令指定模組的套裝程式之一,其 public 類型 (及其巢狀 publicprotected 類型) 應可供所有其他模組中的程式碼存取。exports…to 指令可讓您精確地指定哪些模組或模組的程式碼可以存取匯出的套裝程式,這稱為合格匯出。 

uses。uses 模組指令指定此模組所使用的服務,讓此模組成為服務使用者。service 是類別物件,用於實行介面或擴展 uses 指令中指定的 abstract 類別。

provides…with。provides…with 模組指令指定模組提供服務實作,讓模組成為服務提供者。指令的 provides 部分指定模組的 uses 指令中列出的介面或 abstract 類別,而指令的 with 部分指定服務提供者類別的名稱,該名稱是 implements 介面或 extends abstract 類別。

open、opens 及 opens…to。在 Java 9 之前,reflection 可用於瞭解套裝程式中的所有類型以及類型的所有成員 (甚至是其 private 成員) ,無論您是否允許此功能。因此,沒有任何東西被真正封裝。

模組系統的關鍵優勢是強封裝。預設情況下,模組中的類型無法供其他模組存取,除非其為公用類型您匯出其套裝程式。您僅公開您想要公開的套裝程式。在 Java 9 中,這也適用於 reflection。

允許僅限程式實際執行存取套裝程式。open 模組指令的形式

opens package

指示特定套裝程式public 類型 (及其巢狀 publicprotected 類型) 只能在程式實際執行時,供其他模組中的程式碼存取。此外,指定套裝程式中的所有類型 (以及所有類型的成員) 都可透過 reflection 存取。

允許特定模組僅執行程式實際執行存取套裝程式。opens…to 模組指令的形式

opens package to comma-separated-list-of-modules

指示特定套裝程式public 類型 (及其巢狀 publicprotected 類型) 只能在程式實際執行時,供列示模組中的程式碼存取。指定套裝程式中的所有類型 (以及所有類型的成員) 皆可透過 reflection 指定模組中的程式碼來存取。

允許程式實際執行存取模組中的所有套裝程式。如果指定模組中的所有套裝程式皆可在執行時期存取,並透過 reflection 讓所有其他模組存取,那麽您可以存取 open 整個模組,如下所示:

open module modulename {
   // module directives

Reflection 預設值

依照預設,具有套裝軟體程式實際執行反射存取權的模組會看到套裝軟體的 public 類型 (及其巢狀 publicprotected 類型)。不過,其他模組中的程式碼可以存取公開之套裝程式中的所有類型,以及這些類型內的所有成員,包括透過 setAccessible 存取 private 成員 (如較早的 Java 版本)。

如需有關 setAccessible 和 reflection 的詳細資訊,請參閱 Oracle 文件


Paul Deitel 是 Deitel & Associates 執行長兼技術長,畢業于麻省理工學院,擁有 35 年的運算經驗。他是 Java Champion,擁有超過 22 年的 Java 程式設計經驗。他和合著者 Harvey M. Deitel 博士是世界上最暢銷的程式語言書籍的作者。Paul 為全球產業、政府和學術界的客戶提供 Java、Android、iOS、C#、C++、C 和網際網路程式設計課程。


註:本文摘自《Java Magazine》,2017 年 9 月 /10 月。

深入瞭解