使用 jar 工具建立多版本 Jar

jar 命令可用於建立一個多版本 Jar,其中包含為 Java 8 和 Java 9 編譯的同一類的兩個版本,儘管有警告告訴這些類是相同的:

C:\Users\manouti>jar --create --file MR.jar -C sampleproject-base demo --release 9 -C sampleproject-9 demo
Warning: entry META-INF/versions/9/demo/SampleClass.class contains a class that
is identical to an entry already in the jar

--release 9 選項告訴 jar 在 MRJAR 的版本化條目內,即在 root/META-INF/versions/9 下包含後面的所有內容(sampleproject-9 目錄中的 demo 包)。結果如下:

jar root
  - demo
     - SampleClass.class
  - META-INF
     - versions
        - 9
           - demo
              - SampleClass.class

現在讓我們建立一個名為 Main 的類,它列印 SampleClass 的 URL,併為 Java 9 版本新增它:

package demo;

import java.net.URL;

public class Main {

    public static void main(String[] args) throws Exception {
        URL url = Main.class.getClassLoader().getResource("demo/SampleClass.class");
        System.out.println(url);
    }
}

如果我們編譯這個類並重新執行 jar 命令,我們會收到一個錯誤:

C:\Users\manouti>jar --create --file MR.jar -C sampleproject-base demo --release 9 -C sampleproject-9 demoentry: META-INF/versions/9/demo/Main.class, contains a new public class not found in base entries
Warning: entry META-INF/versions/9/demo/Main.java, multiple resources with same name
Warning: entry META-INF/versions/9/demo/SampleClass.class contains a class that
is identical to an entry already in the jar
invalid multi-release jar file MR.jar deleted

原因是 jar 工具阻止將公共類新增到版本化條目(如果它們也未新增到基本條目中)。這樣做是為了使 MRJAR 為不同的 Java 版本公開相同的公共 API。請注意,在執行時,不需要此規則。它可能只適用於像 jar 這樣的工具。在這種特殊情況下,Main 的目的是執行示例程式碼,因此我們只需在基本條目中新增一個副本。如果該類是我們只需要 Java 9 的新實現的一部分,那麼它可以是非公開的。

要將 Main 新增到根條目,我們首先需要編譯它以定位 Java 9 之前的版本。這可以使用 javac 的新 --release 選項來完成:

C:\Users\manouti\sampleproject-base\demo>javac --release 8 Main.java
C:\Users\manouti\sampleproject-base\demo>cd ../..
C:\Users\manouti>jar --create --file MR.jar -C sampleproject-base demo --release 9 -C sampleproject-9 demo

執行 Main 類顯示 SampleClass 從版本化目錄載入:

C:\Users\manouti>java --class-path MR.jar demo.Main
jar:file:/C:/Users/manouti/MR.jar!/META-INF/versions/9/demo/SampleClass.class