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

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

编辑:我特别想知道是否有任何caching文件/目录级别涉及。 如“在Class版本中caching的目录列表?

以下AFAIK基本上应该做同样的事情,但他们不是:

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

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

另一方面, getResource()ClassLoader版本find了生成的文件。 从这个经验看来,目录列表正在进行某种caching。 我是对的吗?如果是的话,这是在哪里logging?

Class.getResource()的API文档

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

对我来说,这读取“Class.getResource真的调用自己的类加载器的getResource()”。 这和getClass().getClassLoader().getResource() 。 但显然不是。 有人能给我提供一些关于这个问题的启示吗?

回答是否有任何caching正在进行。

我通过运行独立的Java应用程序进一步调查了这一点,该应用程序使用getResourceAsStream ClassLoader方法从磁盘连续加载文件。 我能够编辑文件,并立即反映更改,即该文件是从磁盘重新加载没有caching。

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

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

Class.getResource可以采用一个“相对”的资源名称,这个名字是相对于类的包来处理的。 或者,您可以使用前导斜杠指定“绝对”资源名称。 类加载器资源path总是被认为是绝对的。

所以它们基本上是等价的:

 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"); 

第一次调用相对于.class文件进行search,而后者则相对于类path根进行search。

要debugging这样的问题,我打印url:

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

必须查看它的规格:

  • Class.getResource(String资源)

  • ClassLoader.getResource(String资源)

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

在对资源名称进行这些更改后,此方法将调用委托给其类加载器:如果资源名称以“/”开头,则不变; 否则,在转换“。”之后,软件包名称会预先添加到资源名称中。 至 ”/”。 如果此对象由引导加载程序加载,则该调用将委托给ClassLoader.getSystemResource。

这里的所有答案,以及这个问题的答案都表明,加载绝对的URL,比如“/foo/bar.properties”,通过class.getResourceAsStream(String)class.getClassLoader().getResourceAsStream(String) 。 这不是这种情况,至less不是我的Tomcatconfiguration/版本(目前是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:我也在这里发布

我尝试从input1.txt中读取与我正在尝试读取它的类一起在我的包中

以下工作:

 String fileName = FileTransferClient.class.getResource("input1.txt").getPath(); System.out.println(fileName); BufferedReader bufferedTextIn = new BufferedReader(new FileReader(fileName)); 

最重要的部分是要调用getPath()如果你想正确的path名string格式。 不要使用toString()因为它会添加一些额外的格式化文本,这将完全使用fileName(你可以试试看,看看打印出来)。

花了2小时debugging这个… 🙁

Class.getResources将通过加载对象的类加载器来检索资源。 而ClassLoader.getResource将使用指定的类加载器来检索资源。

Interesting Posts