Class.getResource()和ClassLoader.getResource()有什么区别?


194

我想知道Class.getResource()和之间有什么区别ClassLoader.getResource()

编辑:我特别想知道在文件/目录级别是否涉及任何缓存。如“类别列表中缓存目录列表吗?”

AFAIK以下基本上应该做同样的事情,但事实并非如此:

getClass().getResource() 
getClass().getClassLoader().getResource()

我在摆弄一些报表生成代码时发现了这一点,该代码WEB-INF/classes/从该目录中的现有文件中创建了一个新文件。使用Class中的方法时,可以使用找到部署getClass().getResource()时存在的文件,但是当尝试获取新创建的文件时,我收到了一个空对象。浏览目录清楚地表明新文件在那里。文件名前面有一个正斜杠,如“ /myFile.txt”中所示。

另一方面,的ClassLoader版本getResource()确实找到了生成的文件。从这种经验看来,目录列表存在某种形式的缓存。我是对的,如果是这样,在哪里记录?

API文档开始Class.getResource()

查找具有给定名称的资源。搜索与给定类关联的资源的规则由该类的定义类加载器实现。此方法委派给该对象的类加载器。如果此对象是由引导类加载器加载的,则该方法将委托给ClassLoader.getSystemResource(java.lang.String)。

对我来说,这是“ Class.getResource实际上正在调用其自己的类加载器的getResource()”。这和做一样getClass().getClassLoader().getResource()。但这显然不是。有人可以为我提供一些启发性的东西吗?

Answers:


6

回答是否存在任何缓存的问题。

我通过运行一个独立的Java应用程序进一步研究了这一点,该应用程序使用getResourceAsStream ClassLoader方法从磁盘连续加载文件。我能够编辑该文件,并且更改会立即反映出来,即该文件是从磁盘重新加载而不进行缓存的。

但是: 我正在一个具有几个相互依赖的Maven模块和Web项目的项目中。我使用IntelliJ作为我的IDE来编译和运行Web项目。

我注意到上面的内容似乎不再成立,原因是我正在加载的文件现在被烘焙到jar中并部署到了相关的Web项目中。我只是在尝试更改目标文件夹中的文件后才注意到这一点,但无济于事。这使得好像正在进行缓存。


我也使用过Maven和IntelliJ,所以这是最接近我的环境并且对问题2给出合理解释的答案。
oligofren 2014年

249

Class.getResource可以采用“相对”资源名称,相对于类的包来对待。或者,您可以使用斜杠指定“绝对”资源名称。类加载器资源路径始终被认为是绝对的。

因此,以下基本上是等效的:

foo.bar.Baz.class.getResource("xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("foo/bar/xyz.txt");

这些也是(但它们与上面的有所不同):

foo.bar.Baz.class.getResource("/data/xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("data/xyz.txt");

答案清晰,示例清晰。尽管该帖子实际上旨在获得两个问题的答案,但我现在看到第二个问题有点隐藏。我不确定如何/是否应该更新帖子以反映这一点,但是我想知道的第二件事是(下
一条

2
Class.getResource()版本中是否存在某种类型的缓存?使我相信这是一些jasper报告的生成:我们使用getClass()。getResource(“ / aDocument.jrxml”)来获取jasper xml文件。然后,在同一目录中生成一个二进制jasper文件。尽管getClass()。getResource(“ / aDocument.jasper”)可以清楚地找到同一级别的文档(输入文件),却无法找到它。这就是ClassLoader.getResource()证明有用的地方,因为它似乎不使用目录列表的缓存。但是我找不到关于此的文档。
oligofren 2011年

2
@oligofren:嗯...我不希望 Class.getResource()在那里做任何缓存...
Jon Skeet

1
@JonSkeet为什么this.getClass().getClassLoader().getResource("/");返回null?它不应与this.getClass().getClassLoader().getResource(".");
Asif Mushtaq

@UnKnown:我想您可能应该问一个新的问题。
乔恩·斯基特

22

第一个调用相对于.class文件搜索,而后者则相对于类路径根搜索。

为了调试类似的问题,我打印URL:

System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") );

3
我认为“ classloader根目录”比“ classpath根目录”更准确-只是要挑剔。
乔恩·斯基特

4
如果文件名以“ /”
开头,

2
有趣的是……我遇到了这样一种情况,其中getClass()。getResource(“ / someAbsPath”)返回类型为/path/to/mylib.jar!/someAbsPath和getClass()。getClassLoafer()。getResource(“ / someAbsPath“)返回null ...因此,“类加载器的根”似乎不是一个定义明确的概念...
Pierre Henry


8
@PierreHenry:getClassLoader().getResource("/...")始终返回null-类加载器不会/从路径中删除前导,因此查找始终会失败。仅getClass().getResource()将开始/作为相对于类路径的绝对路径进行处理。
亚伦·迪古拉

17

必须在规格中查找它:

类的getResource()-文档指出了区别:

在对资源名称进行以下更改之后,此方法将调用委托给其类加载器:如果资源名称以“ /”开头,则该名称不变。否则,在将“。”转换后,将包名称放在资源名称之前。至 ”/”。如果此对象是由引导加载程序加载的,则该调用将委派给ClassLoader.getSystemResource。


2
您是否还有是否缓存目录列表的任何信息?当首先查找输入文件,然后在同一目录中使用该文件创建文件时,这是两种方法之间的主要区别。没有找到Class版本,找到ClassLoader版本(都使用“ /file.txt”)。
oligofren 2011年

11

此处的所有这些答案以及该问题的答案均表明,加载绝对URL(例如“ /foo/bar.properties”)与class.getResourceAsStream(String)和对待相同class.getClassLoader().getResourceAsStream(String)。并非如此,至少在我的Tomcat配置/版本(当前为7.0.40)中没有。

MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!  
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!

抱歉,我绝对没有令人满意的解释,但是我想tomcat会在类加载器上做一些肮脏的把戏和他的黑魔法,并造成差异。我class.getResourceAsStream(String)过去经常使用,并且没有任何问题。

PS:我也把这个贴在这里


此行为似乎是Tomcat的错误,该错误已在版本8中修复。我在关于此问题的答案中
LordOfThePigs,2014年

2

Class.getResources将由加载对象的类加载器检索资源。While ClassLoader.getResource将使用指定的类加载器检索资源。


0

我尝试从其中一个包中的input1.txt 和试图读取它的类中读取。

以下作品:

String fileName = FileTransferClient.class.getResource("input1.txt").getPath();

System.out.println(fileName);

BufferedReader bufferedTextIn = new BufferedReader(new FileReader(fileName));

最重要的部分是getPath()如果您想要String格式的正确路径名,则调用。请勿使用,toString()因为它会添加一些额外的格式化文本,从而使fileName总数减少(您可以尝试一下并查看打印结果)。

花了2个小时调试了这个... :(



资源不是文件。它们可能无法从JAR或WAR文件中解压缩,如果不是,则不能使用FileReaderFileInputStream不能用于访问它们。答案不正确。
罗恩侯爵'18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.