使用 JarOutputStream 手動打包 JAR,Manifest 包含 Main-Class、Class-Path、版本號等屬性。解壓對比發現:自動打包與手動打包的 JAR 大小相同、所有文件二進制內容完全一致,但執行 java -jar xxx.jar 時自動打包版報錯「找不到主類」。
ZIP 条目路徑分隔符不一致:
ZipEntry 時若使用反斜杠 `\`,解壓工具(如 7-Zip、WinRAR)雙向兼容,但 JVM 類加載器只識別 `/`test\Helloworld.class,而類加載器查找 test/Helloworld.class,從而找不到主類String className = "test.Helloworld";
String entryName = className.replace('.', File.separatorChar) + ".class"; // 產生 "test\Helloworld.class"
ZipEntry entry = new ZipEntry(entryName);
jarOut.putNextEntry(entry);
String className = "test.Helloworld";
String entryName = className.replace('.', '/') + ".class"; // 固定產生 "test/Helloworld.class"
ZipEntry entry = new ZipEntry(entryName);
jarOut.putNextEntry(entry);
# 查看 JAR 內部路徑分隔符
jar tf your.jar | head -20
# 正確輸出應為:
# META-INF/
# META-INF/MANIFEST.MF
# test/Helloworld.class
File.separator 或 File.separatorCharClass-Path 同樣要求使用正斜杠分隔new JarFile(jar).entries().asIterator().allMatch(e -> !e.getName().contains("\\"))JAR 格式本質是 ZIP 文件,但 JAR 規範 明確要求:
「所有路徑名稱必須使用正斜杠 `/` 作為分隔符,與平台無關。」
這也是 Java「一次編寫,到處運行」在打包層面的體現。