加载 .jar 资源时使用 ClassLoader

Using ClassLoader when loading .jar resources

我只是不明白为什么使用 ClassLoader 会导致这两种情况的行为不同。有人可以解释一下 how/why ClassLoader 更改了搜索,因此它需要进入 jar 的完整路径吗?

package com.example;
import java.io.InputStream;

public class SomeClass {
  private static InputStream stm;
  static {
    for (final String s : new String[] { "file.png", "com/example/file.png", "/com/example/file.png" }) {
      // case 1 - w/o classLoader
      stm = SomeClass.class.getResourceAsStream(s);
      System.out.println("w/o          : " + (stm == null ? "FAILED to load" : "loaded") + " " + s);

      // case 2 - w/ classLoader
      stm = SomeClass.class.getClassLoader().getResourceAsStream(s);
      System.out.println("w/classloader: " + (stm == null ? "FAILED to load" : "loaded") + " " + s);
    }
  }

  public static void main(final String args[]) {}
}

生产:

w/o          : loaded file.png
w/classloader: FAILED to load file.png
w/o          : FAILED to load com/example/file.png
w/classloader: loaded com/example/file.png
w/o          : loaded /com/example/file.png
w/classloader: FAILED to load /com/example/file.png

因为根据您调用的 getResourceAsStream() 方法,路径的评估方式不同。
如果您在 class com.example.SomeClass 上调用 Class.getResourceAsStream(),那么如果路径不以 / 开头,则相对于 SomeClass 评估路径,因此 file.png 变为 /com/example/file.png 并且 com/example/file.png 变为 /com/example/com/example/file.png.
如果你在它的 ClassLoader 上调用 ClassLoader.getResourceAsStream(),那么路径是隐含的绝对路径并且不能以 / 开头,所以 file.png 变成 /file.pngcom/example/file.png 变成 /com/example/file.png.
如果你使用像/com/example/file.png这样的绝对路径,你必须使用Class方法。

不幸的是,ClassLoader.getResourceAsStream() 的这种隐式绝对性仅在 Class.getResourceAsStream() 的文档中隐式记录,其中指出它在委托给 ClassLoaders 方法之前去除了前导斜线。