java launcher_JAR清单类路径不仅适用于Java Application Launcher
java launcher
自從我開始學(xué)習(xí)Java以來??,我?guī)缀跻呀?jīng)知道, 清單文件中的Class-Path標(biāo)頭字段為可執(zhí)行JAR (具有由另一個稱為Main-Class清單指定應(yīng)用程序起點的 JAR)指定了相對運行時類路徑。 一個同事最近碰到一個讓我感到驚訝,因為它證明了一個問題JAR文件的清單的Class-Path條目也影響編譯時類路徑時包含在類路徑中包含JAR在運行javac的 。 這篇文章演示了這種新變化。
Java教程的部署跟蹤的“ 將類添加到JAR文件的類路徑 ”部分指出:“您指定要包含在applet或應(yīng)用程序清單文件中的Class-Path頭字段中的Class-Path 。” 該部分還指出:“通過使用清單中的Class-Path標(biāo)頭,可以避免在調(diào)用Java運行應(yīng)用程序時指定長的-classpath標(biāo)志。” 這兩個句子從本質(zhì)上總結(jié)了我一直如何想到清單文件中的Class-Path標(biāo)頭:作為包含的JAR的類路徑是通過Java應(yīng)用程序啟動器( java可執(zhí)行文件)執(zhí)行的。
事實證明,JAR清單中的Class-Path條目會影響Java編譯器( javac ),就像它會影響Java應(yīng)用程序啟動器( java )一樣。 為了演示這一點,我將使用一個簡單的接口( PersonIF ),一個實現(xiàn)該接口的簡單類( Person )和一個簡單的Main類,該類使用實現(xiàn)該接口的類。 接下來顯示這些的代碼清單。
PersonIF.java
public interface PersonIF {void sayHello(); }人.java
import static java.lang.System.out;public class Person implements PersonIF {public void sayHello(){out.println("Hello!");} }Main.java
public class Main {public static void main(final String[] arguments){final Person person = new Person();person.sayHello();} }從上面的代碼清單可以看出, Main類依賴于(使用) Person類,而Person類依賴于(實現(xiàn)) PersonIF 。 我將把PersonIF.class文件放在它自己的名為PersonIF.jar JAR中,并將該JAR存儲在(不同的)子目錄中。 Person.class文件將存在于其自己的Person.jar JAR文件中,并且該JAR文件包括MANIFEST.MF file ,該MANIFEST.MF file的Class-Path標(biāo)頭引用了相對子目錄中的PersonIF.jar 。
現(xiàn)在,我將嘗試僅使用類路徑中的當(dāng)前目錄從Main.java編譯Main.class 。 當(dāng)javac在單獨的子目錄中找不到PersonIF.jar時,我以前曾期望編譯會失敗。 但是,它不會失敗!
這讓我感到驚訝。 當(dāng)我沒有明確指定PersonIF.class (或包含它的JAR)作為通過-cp標(biāo)志提供的classpath的值時,為什么要編譯此文件? 通過使用帶有-verbose標(biāo)志的javac可以看到答案。
javac -verbose的輸出提供“ 源文件的搜索路徑”和“ 類文件的搜索路徑”。 在這種情況下,“類文件的搜索路徑”很重要,因為我已經(jīng)將PersonIF.java和Person.java源文件移到了一個完全不相關(guān)的目錄中,而不是在那些指定的搜索路徑中。 有趣的是,即使我沒有在-cp的值中指定此JAR(甚至目錄),類文件的搜索路徑(以及源文件的搜索路徑)仍包含archive/PersonIF.jar 。 這表明Oracle提供的Java編譯器考慮在類Class-Path上指定的任何JAR的MANIFEST.MF的Class-Path頭中指定的類路徑內(nèi)容。
下一個屏幕快照演示了如何運行新編譯的Main.class類,以及PersonIF.class從archive/PersonIF.jar獲取依賴PersonIF.class archive/PersonIF.jar而無需在傳遞給Java應(yīng)用程序啟動程序的java -cp標(biāo)志的值中指定依賴PersonIF.class 。 我希望運行時行為是這種方式,盡管坦白地說我從未嘗試過,甚至從未考慮過使用其MANIFEST.MF文件沒有Main-Class標(biāo)頭(不可執(zhí)行的JAR)的JAR來執(zhí)行此操作。 在此示例中, Person.jar清單文件未指定Main-Class頭,而僅指定了Class-Path頭,但是在使用java調(diào)用時仍能夠在運行時使用此類路徑內(nèi)容。
本文的最終演示涉及從JAR文件中刪除Class-Path標(biāo)頭和關(guān)聯(lián)的值,并嘗試使用javac和相同的命令行指定的classpath進(jìn)行編譯。 在這種情況下,包含Person.class的JAR被稱為Person2.jar ,下面的屏幕快照演示了其MANIFEST.MF文件沒有Class-Path標(biāo)頭。
下一個屏幕快照展示了使用javac現(xiàn)在失敗的原因,這是因為,正如預(yù)期的那樣,沒有在類路徑上顯式指定PersonIF.class ,并且不再通過引用JAR的MANIFEST.MF Class-Path頭使它可用。類路徑。
從上一個屏幕快照中我們可以看到,源文件和類文件的搜索路徑不再包含archive/PersonIF.jar 。 沒有可用的JAR, javac將無法找到PersonIF.class并報告錯誤消息:“找不到PersonIF.class類文件。”
一般觀察
- MANIFEST.MF文件中的Class-Path標(biāo)頭不依賴于存在于同一JAR的MANIFEST.MF文件中的Main-Class標(biāo)頭。
- 具有Class-Path清單標(biāo)頭的JAR將使這些類路徑條目可用于Java類加載器,而不管該JAR是使用java -jar ...執(zhí)行還是僅放置在較大Java應(yīng)用程序的類路徑上。
- 因為在JAR清單文件中使用Class-Path的范圍并不限于正在執(zhí)行其Main-Class JAR,所以這些依賴可能潛在地?zé)o意中滿足了類依賴(即使版本不正確),而不是解析明確指定的classpath條目。 在構(gòu)造帶有指定Class-Path清單的JAR時,或在清單文件中使用帶有Class-Path的第三方JAR時,建議謹(jǐn)慎。
- 有時低估了JAR清單文件的重要性,但是該主題提醒人們了解特定JAR清單文件中的內(nèi)容的有用性。
- 本主題提醒您可以不時運行javac而無需-verbose來查看其最新信息即可收集的見解。
- 每當(dāng)將JAR放置在javac編譯器或java應(yīng)用程序啟動器的類路徑上時,您不僅在類路徑中的那個JAR中放置了更多的類定義; 您還將在該編譯器或應(yīng)用程序啟動器的Class-Path上放置該JAR清單清單的Class-Path引用的所有類和JAR。
結(jié)論
Java類加載器可以在許多地方加載用于構(gòu)建和運行Java應(yīng)用程序的類。 正如本文所展示的,JAR的MANIFEST.MF文件的Class-Path標(biāo)頭是另一個影響點,可以影響類加載器在運行時和編譯時加載的類。 使用Class-Path不會只影響“可執(zhí)行”的JAR(在清單文件中指定了Main-Class標(biāo)頭,并使用java -jar ...運行),但可能會影響已加載的類以進(jìn)行編譯以及任何Java應(yīng)用程序執(zhí)行,其中帶有包含Class-Path標(biāo)頭的清單文件的JAR位于類路徑上。
翻譯自: https://www.javacodegeeks.com/2015/09/jar-manifest-class-path-is-not-for-java-application-launcher-only.html
java launcher
總結(jié)
以上是生活随笔為你收集整理的java launcher_JAR清单类路径不仅适用于Java Application Launcher的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux命令复制文件到指定目录(lin
- 下一篇: 硅胶的化学成分是什么 硅胶简介