[英]Java empty path convention, especially that used in ClassLoader.getResources
今天,我很驚訝(可能是由於缺乏經驗)發現你可以,並且它實際上很有用,將一個空路徑(字面上是一個空字符串)傳遞給ClassLoader.getResources
,即ClassLoader.getSystemClassLoader().getResources("")
。 從某些測試中,這將返回我的應用程序.class
文件所在的一個或兩個目錄(並且不包括第三方軟件包的目錄)。 (示例用法: 獲取Classpath中的所有類 。)
據推測,這是因為Java System ClassLoader是加載我自己的應用程序類的三個ClassLoader之一(參見http://www.oracle.com/technetwork/articles/javase/classloaders-140370.html ),所以這並不奇怪該URL返回指向我的應用程序類文件的目錄。
但是為什么,以及如何,空字符串實現這一目標? 我沒有發現它有記錄。 這是更常見的Java約定的空路徑衍生物嗎? 這當然不是Linux的-你不能cd
到在bash空路徑。 如果有人能幫助我理解這一點,我會很感激。
在另一個注釋中,我注意到getResources(".")
實現了相同的功能。
評論討論的補充
public class myTest {
public static void main(String[] args) throws Exception {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) classLoader).getURLs();
for (int n = 0; n < urls.length; n++)
System.out.println(urls[n]); //lists external.jar
Enumeration<URL> roots = classLoader.getResources(".");
while (roots.hasMoreElements()) {
URL url = roots.nextElement();
System.out.println("getResources: " + url); //does not list external.jar
}
}
}
要執行的命令: java -cp ".:external.jar" myTest
當給定資源名稱“”或“。”時,為什么getResources(String)
調用匹配作為目錄的所有類路徑條目?
我只能推測。 對於它的價值,我認為這是特定ClassLoader
的實現細節。 方式“”和“。” 從文件系統用戶的角度來看,資源名稱的處理方式有點直觀。
...如何?
默認的OpenJDK應用程序ClassLoader
(也稱為System ClassLoader
) sun.misc.Launcher$AppClassLoader
是一個URLClassLoader
后代,其URL搜索路徑包含“java.class.path”系統屬性的值。 它的getResources
( getResource
)方法最終委托給sun.misc.URLClassPath$FileLoader.getResource(String, boolean)
,它執行以下操作:
url = new URL(getBaseURL(), ParseUtil.encodePath(name, false));
...
file = new File(dir, name.replace('/', File.separatorChar)); // dir is the equivalent of getBaseURL()'s path component
...
if (file.exists()) {
return new sun.misc.Resource() {
...
public URL getURL() { return url; } // eventually returned by the ClassLoader
}
}
拋開所有URL解析,資源名稱基本上被視為相對文件系統路徑,並且對於加載器的搜索路徑條目是“絕對化的”。 因此, name
參數為“”或“。”。 匹配搜索路徑條目本身。 換句話說,所有頂級類路徑條目都匹配並返回,就好像它們都位於同一根目錄下一樣。 請注意,這不適用於JAR類路徑條目,而是由sun.misc.URLClassPath$JarLoader
處理。
為什么這些getResources
調用也不匹配JAR類路徑條目? 為什么這些類路徑條目包含在URLClassLoader.getURLs()
返回的數組中?
API明智...
這是兩種不相關的方法,每種方法都有不同的用途。 有時他們“只是發生”以產生相同或相似的輸出 - 然而他們的規格卻暗示任何形式的行為相互一致。
根據URLClassLoader
對術語“資源”的具體定義, getResources
被指定為在其搜索路徑下返回文件,目錄或JAR條目。 當它們表示目錄時,它也恰好返回搜索路徑條目本身的事實,它的規范沒有解決它,因此應該被視為實現細節(也可能是次要的規范違規),而不是依賴它們。 同樣,它不返回JAR搜索路徑條目,而與前者不一致,這一事實並不反對其規范。
另一方面, getURLs
返回在實例化時提供的確切的1個搜索路徑條目。
實現明智...
與sun.misc.URLClassPath$FileLoader
不同,如前所述,它根據每個搜索路徑條目的文件系統路徑解析資源名稱, sun.misc.URLClassPath$JarLoader
嘗試通過JarFile.getEntry(name)
進行直接匹配,對於“”,很可能是“。”,條目名稱,顯然都失敗了。 但即使兩個URLClassPath.Loader
都以相同的方式解釋資源名稱,事情也無法按預期工作,因為嵌入式JAR文件系統不支持根目錄的概念。
那么我應該如何檢索所有類路徑條目?
要獨立於系統ClassLoader
生效,請使用類似的東西
String[] classPathEntries = System.getProperty("java.class.path").split(File.pathSeparator);
,最好在您的main
方法的早期,在任何第三方代碼提供修改屬性的機會之前。
ClassLoader.getSystemClassLoader()
的返回類型為java.lang.ClassLoader
。 我們怎么知道(肯定)返回的實例是sun.misc.Launcher$AppClassLoader
?
我們真的沒有。 系統類加載器是依賴於實現和可替換的。 我們所能做的一如既往地是測試,例如,
try {
ClassLoader sysCl = ClassLoader.getSystemClassLoader();
// not using single-arg Class.forName, since it would use the ClassLoader of this class,
// which, in the worst-case scenario of being a non-delegating loader, could attempt to load AppClassLoader itself
if (Class.forName("sun.misc.Launcher$AppClassLoader", false, sysCl).isAssignableFrom(sysCl.getClass())) {
// default implementation, _most likely_ a URLClassLoader subclass
}
else {
// System ClassLoader overridden, or not on OpenJDK
}
}
catch (ReflectiveOperationException roe) {
// most likely not on OpenJDK
}
並采取相應行動。
sun.misc.URLClassPath
的源代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.