Preferred way of loading resources in Java

I would like to know the best way of loading a resource in Java:

  • this.getClass().getResource() (or getResourceAsStream()),
  • Thread.currentThread().getContextClassLoader().getResource(name),
  • System.class.getResource(name).
143692 次浏览

这在一定程度上取决于,如果你是派生类中的 actually,你希望发生什么。

例如,假设 SuperClass在 A.jar 中,SubClass在 B.jar 中,并且您正在 SuperClass中声明的实例方法中执行代码,但是其中 this引用了 SubClass的实例。如果你使用 this.getClass().getResource(),它将看起来相对于 SubClass,在 B.jar。我怀疑这不是 通常的要求。

就个人而言,我可能会使用 Foo.class.getResourceAsStream(name)最经常-如果你已经知道资源的名称后,你已经确定它是相对于 Foo的位置,这是最健壮的方式做它 IMO。

Of course there are times when that's 没有 what you want, too: judge each case on its merits. It's just the "I know this resource is bundled with this class" is the most common one I've run into.

根据你想要的解决方案..。

getResource/getResourceAsStream()将从它所调用的类中获得两个东西..。

  1. 类装入器
  2. 出发地点

所以如果你这么做了

this.getClass().getResource("foo.txt");

它将尝试从与“ this”类相同的包中加载 foo.txt,并使用“ this”类的类加载器。如果您在前面加上一个“/”,那么您绝对是在引用资源。

this.getClass().getResource("/x/y/z/foo.txt")

将从“ this”的类装入器和 x.y.z 包中装入资源(它将需要与包中的类位于同一目录中)。

Thread.currentThread().getContextClassLoader().getResource(name)

will load with the context class loader but will not resolve the name according to any package (it must be absolutely referenced)

System.class.getResource(name)

Will load the resource with the system class loader (it would have to be absolutely referenced as well, as you won't be able to put anything into the java.lang package (the package of System).

看看源头就知道了。还指示 getResourceAsStream 只对从 getResource 返回的 URL 调用“ openStream”并返回。

我搜索三个地方,如下所示。欢迎评论。

public URL getResource(String resource){


URL url ;


//Try with the Thread Context Loader.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if(classLoader != null){
url = classLoader.getResource(resource);
if(url != null){
return url;
}
}


//Let's now try with the classloader that loaded this class.
classLoader = Loader.class.getClassLoader();
if(classLoader != null){
url = classLoader.getResource(resource);
if(url != null){
return url;
}
}


//Last ditch attempt. Get the resource from the classpath.
return ClassLoader.getSystemResource(resource);
}

I know it really late for another answer but I just wanted to share what helped me at the end. It will also load resources/files from the absolute path of the file system (not only the classpath's).

public class ResourceLoader {


public static URL getResource(String resource) {
final List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
classLoaders.add(Thread.currentThread().getContextClassLoader());
classLoaders.add(ResourceLoader.class.getClassLoader());


for (ClassLoader classLoader : classLoaders) {
final URL url = getResourceWith(classLoader, resource);
if (url != null) {
return url;
}
}


final URL systemResource = ClassLoader.getSystemResource(resource);
if (systemResource != null) {
return systemResource;
} else {
try {
return new File(resource).toURI().toURL();
} catch (MalformedURLException e) {
return null;
}
}
}


private static URL getResourceWith(ClassLoader classLoader, String resource) {
if (classLoader != null) {
return classLoader.getResource(resource);
}
return null;
}


}

我尝试了上面建议的许多方法和功能,但它们在我的项目中不起作用。不管怎样,我已经找到了解决办法,这就是:

try {
InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
img = ImageIO.read(path);
} catch (IOException e) {
e.printStackTrace();
}