Java中加载资源的首选方法
我想知道用Java加载资源的最佳方法:Java中加载资源的首选方法,java,resources,Java,Resources,我想知道用Java加载资源的最佳方法: this.getClass().getResource()(或getResourceAsStream()) Thread.currentThread().getContextClassLoader().getResource(名称) System.class.getResource(名称) 好吧,这在一定程度上取决于如果您实际上在派生类中,您希望发生什么 例如,假设超类在A.jar中,子类在B.jar中,您在超类中声明的实例方法中执行代码,但其中此引用了
this.getClass().getResource()(或getResourceAsStream())
Thread.currentThread().getContextClassLoader().getResource(名称)
System.class.getResource(名称)
超类
在A.jar中,子类
在B.jar中,您在超类
中声明的实例方法中执行代码,但其中此
引用了子类
的实例。如果您使用this.getClass().getResource()
,它将与B.jar中的子类相对。我想这通常不是必需的
就我个人而言,我可能会经常使用Foo.class.getResourceAsStream(name)
——如果您已经知道您要查找的资源的名称,并且确定它相对于Foo
的位置,那么这是最可靠的方法
当然,有时这也不是你想要的:根据案情判断每个案件。只是“我知道这个资源与这个类捆绑在一起”是我遇到的最常见的一个问题。根据您的需要制定解决方案
getResource
/getResourceAsStream()
将从调用它的类中获得两样东西
类加载器
起始位置
所以如果你这样做了
this.getClass().getResource("foo.txt");
它将尝试从与“this”类相同的包以及“this”类的类加载器中加载foo.txt。如果在前面加上“/”,则绝对是在引用资源
this.getClass().getResource("/x/y/z/foo.txt")
将从“this”的类加载器和x.y.z包中加载资源(它需要与该包中的类位于同一目录中)
将使用上下文类加载器加载,但不会根据任何包解析名称(必须绝对引用)
将使用系统类加载器加载资源(它也必须被绝对引用,因为您无法将任何内容放入java.lang包(system的包)
只需查看源代码。还表明getResourceAsStream只调用从getResource返回的URL上的“openStream”,并返回该URL。我搜索了三个地方,如下所示。欢迎评论
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);
}
我知道现在回答另一个问题已经很晚了,但我只想在最后分享帮助我的东西。它还将从文件系统的绝对路径(不仅仅是类路径)加载资源/文件
公共类资源加载器{
公共静态URL getResource(字符串资源){
最终列表类加载器=新的ArrayList();
添加(Thread.currentThread().getContextClassLoader());
add(ResourceLoader.class.getClassLoader());
用于(类加载器类加载器:类加载器){
最终URL=getResourceWith(类加载器,资源);
如果(url!=null){
返回url;
}
}
最终URL systemResource=ClassLoader.getSystemResource(资源);
if(systemResource!=null){
返回系统资源;
}否则{
试一试{
返回新文件(resource.toURI().toul();
}捕获(格式错误){
返回null;
}
}
}
私有静态URL getResourceWith(类加载器类加载器字符串资源){
if(类加载器!=null){
返回classLoader.getResource(resource);
}
返回null;
}
}
我尝试了上面建议的许多方法和功能,但它们在我的项目中不起作用。总之,我找到了解决方案,现在是:
try {
InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
img = ImageIO.read(path);
} catch (IOException e) {
e.printStackTrace();
}
skeet:如果我们是在超类的实例方法中执行语句,那么“您正在超类的实例方法中执行代码,但这指的是子类的实例”中的疑问是“this”将引用超类而不是子类。@Suresh:不,不会。试试看!创建两个类,使一个从另一个派生,然后在超类中打印输出this.getClass()
。创建子类的实例并调用该方法…它将打印出子类的名称,而不是超类的名称。谢谢,子类实例方法调用了超类的方法。我想知道的是,使用this.getResourceAsStream是否只能从与this clas来源的jar相同的jar加载资源,而不是从同一jar加载资源我是另一个jar。据我估计,是类加载器加载了资源,当然不会被限制只从一个jar加载?AIK包名称不重要,是类加载器的类路径起作用。@Bart如果你看源代码,你会注意到在类上调用getResource时,类名确实很重要。The此调用所做的第一件事是调用“resolveName”,如果合适,它会添加包前缀。resolveName的Javadoc是“如果名称不是绝对的,则添加包名称前缀删除前导”/“如果名称是绝对的”啊,我明白了。这里绝对的意思是相对于类路径,而不是绝对文件系统。我只想补充一点,您应该始终检查从getResourceAsStream()返回的流不为null,因为如果资源不在类路径内,则为null。另外值得注意的是,使用上下文类加载器允许在运行时通过线程#setContextClassLoader
更改类加载器。如果在程序执行时需要修改类路径,这非常有用。谢谢,这是一个好主意在我需要的时候。我正在查看代码中的注释,最后一条听起来很有趣。不是所有的资源都是从类路径加载的吗?ClassLoader.getSystemResource()会涵盖哪些情况
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();
}