Class.getResource()
和ClassLoader.getResource()
之间有什么区别?edit:我特别想知道文件/目录级别上是否涉及任何缓存。就像“是否在Class版本中缓存目录列表?”中的以下内容基本相同,但实际上它们不是:
getClass().getResource()
getClass().getClassLoader().getResource()
我在处理一些报表生成代码时发现了这一点,该代码从该目录中的现有文件在
WEB-INF/classes/
中创建了一个新文件。使用Class中的方法时,可以使用getClass().getResource()
找到部署时存在的文件,但是当尝试获取新创建的文件时,我收到了一个空对象。浏览目录清楚地表明新文件在那里。文件名前面有一个正斜杠,如“ /myFile.txt”。另一方面,
ClassLoader
的getResource()
版本确实找到了生成的文件。从这种经验看来,目录列表存在某种形式的缓存。 从
Class.getResource()
上的API文档中找到文档吗?查找具有给定名称的资源
。
搜索与给定类相关的资源的规则由定义该类的
类加载器实现。
此方法委托给该对象的
类加载器。如果此对象是由引导类加载器加载的,则该方法将委托给
ClassLoader.getSystemResource(java.lang.String)。
对我来说,这是“ Class.getResource实际上正在调用其自己的类加载器的getResource()”。这与执行
getClass().getClassLoader().getResource()
相同。但这显然不是。有人可以为我提供一些启发性的东西吗?#1 楼
为了回答是否存在任何缓存问题。我运行了一个独立的Java应用程序,进一步研究了这一点,该应用程序使用getResourceAsStream ClassLoader方法从磁盘连续加载文件。我能够编辑文件,并且更改会立即反映出来,例如,文件已从磁盘重新加载而不进行缓存。
但是:
我正在一个有多个Maven的项目中工作相互依赖的模块和Web项目。我正在使用IntelliJ作为我的IDE来编译和运行Web项目。
我注意到上面的内容似乎不再成立,原因是现在正在加载的文件已经被烘焙放入jar并部署到相关的Web项目中。我只是在尝试更改目标文件夹中的文件后才注意到这一点,但无济于事。这使得好像正在进行缓存。
#2 楼
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");
评论
答案清晰,示例清晰。尽管该帖子实际上旨在获得两个问题的答案,但我现在看到第二个问题有点隐藏。非常不确定我应该如何/是否应该更新帖子以反映这一点,但是我想知道的第二件事是(下一条评论):
–寡核苷酸
2011年7月7日在16:04
Class.getResource()版本中是否存在某种类型的缓存?使我相信这是一些jasper报告的生成:我们使用getClass()。getResource(“ / aDocument.jrxml”)来获取jasper xml文件。然后,在同一目录中生成一个二进制jasper文件。尽管getClass()。getResource(“ / aDocument.jasper”)可以清楚地找到同一级别的文档(输入文件),却无法找到它。这就是ClassLoader.getResource()证明有用的地方,因为它似乎不使用目录列表的缓存。但是我找不到关于此的文档。
–寡核苷酸
2011年7月7日在16:08
@oligofren:嗯...我不希望Class.getResource()在那里做任何缓存...
–乔恩·斯基特(Jon Skeet)
2011年7月7日在16:18
@JonSkeet为什么this.getClass()。getClassLoader()。getResource(“ /”);返回空值?它不应与this.getClass()。getClassLoader()。getResource(“。”);相同。
–阿西夫·穆斯塔克(Asif Mushtaq)
18年2月16日在22:20
@UnKnown:我想您可能应该问一个新的问题。
–乔恩·斯基特(Jon Skeet)
18年2月17日在8:06
#3 楼
第一个调用相对于.class
文件进行搜索,而第二个相对于类路径根目录进行搜索。要调试类似的问题,我打印URL:
System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") );
评论
我认为“ classloader根目录”比“ classpath根目录”更准确-只是要挑剔。
–乔恩·斯基特(Jon Skeet)
2011年7月7日在10:14
如果文件名以“ /”开头,两者都可以搜索“绝对路径”
–寡核苷酸
2011年7月7日在15:59
有趣的是……我遇到了这样一种情况:getClass()。getResource(“ / someAbsPath”)返回类型为/path/to/mylib.jar!/someAbsPath和getClass()。getClassLoafer()。getResource(“ / someAbsPath“)返回null ...因此,” classloader的根目录“似乎不是一个很好定义的概念...
–皮埃尔·亨利(Pierre Henry)
13年4月16日在14:35
参见stackoverflow.com/questions/13269556/…
–皮埃尔·亨利(Pierre Henry)
13年4月16日在14:36
@PierreHenry:getClassLoader()。getResource(“ / ...”)始终返回null-类加载器不会从路径中删除前导/,因此查找始终会失败。只有getClass()。getResource()将开始/作为相对于类路径的绝对路径进行处理。
–亚伦·迪古拉(Aaron Digulla)
2013年4月16日14:43
#4 楼
必须在规格中查找它:Class.getResource(String resource)
ClassLoader.getResource(String resource)
Class的getResource( )-文档指出了不同之处:
此方法在对资源名称进行了这些更改之后,将调用委托给其类加载器:如果资源名称以“ /”开头,则为不变否则,将包名称转换为“。”之后的资源名称之前。至 ”/”。如果此对象是由引导加载程序加载的,则该调用将委派给ClassLoader.getSystemResource。
评论
您是否还有是否缓存目录列表的任何信息?当首先查找输入文件,然后在同一目录中使用该文件创建文件时,这是两种方法之间的主要区别。 Class版本找不到它,ClassLoader版本找到了(两者都使用“ /file.txt”)。
–寡核苷酸
2011年7月7日在16:22
#5 楼
此处的所有这些答案以及该问题的答案都表明,通过class.getResourceAsStream(String)
和class.getClassLoader().getResourceAsStream(String)
处理加载绝对URL(如“ /foo/bar.properties”)的方式相同。并非如此,至少在我的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年7月6日下午0:31
#6 楼
Class.getResources
将由加载对象的类加载器检索资源。虽然ClassLoader.getResource
将使用指定的类加载器检索资源。#7 楼
我尝试从我的一个软件包中的input1.txt以及试图读取它的类中读取。以下作品:
String fileName = FileTransferClient.class.getResource("input1.txt").getPath();
System.out.println(fileName);
BufferedReader bufferedTextIn = new BufferedReader(new FileReader(fileName));
最重要的部分是如果您要使用String格式的正确路径名,请致电
getPath()
。请勿使用toString()
,因为它会添加一些额外的格式化文本,从而使fileName总计减少(您可以尝试一下并查看打印出来的内容)。花了2个小时调试了此...:(
评论
那Class.getResourceAsStream()呢?
–Lu55
18年1月15日在15:34
资源不是文件。它们可能不会从JAR或WAR文件中解压缩,否则,不能使用FileReader或FileInputStream来访问它们。答案不正确。
–user207421
18年7月3日在2:30
评论
我也使用过Maven和IntelliJ,所以这是最接近我的环境并且对问题#2有合理解释的答案。
–寡核苷酸
2014年1月10日上午9:55