类加载器资源路径总是绝对的?

Classloader resource paths are always absolute?

在关于 class 加载方法之间差异的流行 answer 中,Jon Skeet 指出,

Classloader resource paths are always deemed to be absolute.

一个更受欢迎的 answer 用一个例子证实了这个说法。

ClassLoader.getResourceAsStream(path) will consider all paths to be absolute paths. So calling String.getClassLoader().getResourceAsString("myfile.txt") and String.getClassLoader().getResourceAsString("/myfile.txt") will both look for a file in your classpath at the following location: ./myfile.txt.

忽略示例无法编译的事实,共识表明前导正斜杠与 ClassLoader 无关。

一个简单的测试表明并非如此。

Foo.class.getClassLoader().getResource("test.xml") // file
Foo.class.getClassLoader().getResource("/test.xml") // null

我只是将路径 files/test.xml 添加到测试项目的 class 路径,其中包含一个名为 Foo 的 class 包含一个 main() 方法打印出这两个调用的结果。既然有数百人对上述答案投了赞成票,我还缺少什么? ClassLoaders 是绝对的,还是取决于输入名称的结构?


这个Oracle blog post对我的理解很有帮助。

最终从资源名称构造一个URL的方法是URLClassPath.JarLoader.checkResource().

显然不是。

由 class 加载程序来解释 getResource(name) 中的 name

查看URLClassLoader的源代码,最终调用

new URL(baseURL, name)

这里重要的是name是绝对的还是相对的

有可能,对于某些baseURL,绝对/foo/bar和相对foo/bar具有相同的效果。特别是 classpaths

中的 "jar file URL" 总是如此
baseURL:       jar:file:/home/duke/duke.jar!/

 foo/bar  ->   jar:file:/home/duke/duke.jar!/foo/bar 
/foo/bar  ->   jar:file:/home/duke/duke.jar!/foo/bar