【发布时间】:2021-01-25 21:22:39
【问题描述】:
我想知道在 Java 中加载资源的最佳方式:
-
this.getClass().getResource() (or getResourceAsStream()), -
Thread.currentThread().getContextClassLoader().getResource(name), -
System.class.getResource(name)。
【问题讨论】:
我想知道在 Java 中加载资源的最佳方式:
this.getClass().getResource() (or getResourceAsStream()),Thread.currentThread().getContextClassLoader().getResource(name),System.class.getResource(name)。【问题讨论】:
嗯,如果您实际上在派生类中,这部分取决于您想要发生的事情。
例如,假设 SuperClass 在 A.jar 中,SubClass 在 B.jar 中,并且您在 SuperClass 中声明的实例方法中执行代码,但其中 this 指的是SubClass。如果您使用this.getClass().getResource(),它将看起来相对于 B.jar 中的SubClass。我怀疑这通常不是必需的。
就我个人而言,我可能最常使用Foo.class.getResourceAsStream(name) - 如果您已经知道您所追求的资源的名称,并且您确定它相对于Foo 的位置,那么这是最可靠的方法做海事组织。
当然,有时这也不是您想要的:根据案情来判断每个案件。只是“我知道这个资源与这个类捆绑在一起”是我遇到的最常见的。
【讨论】:
this.getClass()。创建一个子类的实例并调用该方法...它会打印出子类的名称,而不是超类的名称。
根据你的需要制定解决方案...
getResource/getResourceAsStream() 将从调用它的类中得到两件事...
如果你这样做了
this.getClass().getResource("foo.txt");
它将尝试从与“this”类和“this”类的类加载器相同的包中加载 foo.txt。如果您在前面加上“/”,那么您绝对是在引用该资源。
this.getClass().getResource("/x/y/z/foo.txt")
将从“this”的类加载器和 x.y.z 包中加载资源(它需要与该包中的类位于同一目录中)。
Thread.currentThread().getContextClassLoader().getResource(name)
将使用上下文类加载器加载,但不会根据任何包解析名称(必须绝对引用)
System.class.getResource(name)
将使用系统类加载器加载资源(它也必须被绝对引用,因为您无法将任何内容放入 java.lang 包(System 的包)中。
只需查看源代码即可。也表示 getResourceAsStream 只是在 getResource 返回的 URL 上调用“openStream”并返回。
【讨论】:
Thread#setContextClassLoader 更改类加载器。如果您需要在程序执行时修改类路径,这很有用。
我搜索三个地方,如下所示。欢迎评论。
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);
}
【讨论】:
我知道另一个答案真的很晚,但我只是想分享最后帮助我的东西。它还将从文件系统的绝对路径(不仅是类路径)加载资源/文件。
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();
}
【讨论】:
this.getClass().getResourceAsStream()。如果您查看getResourceAsStream 方法的源代码,您会注意到它的作用与您相同,但方式更智能(如果在类中找不到ClassLoader,则回退)。它还表明您可以在代码中的getClassLoader 上遇到潜在的null ...
this.getClass().getResourceAsStream() 不适合我,所以我使用它。我认为有些人会面临像我这样的问题。