Java Class.getResource() 和 ClassLoader.getResource() 有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6608795/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between Class.getResource() and ClassLoader.getResource()?
提问by oligofren
I wonder what the difference is between Class.getResource()
and ClassLoader.getResource()
?
我想知道Class.getResource()
和之间有什么区别ClassLoader.getResource()
?
edit: I especially want to know if any caching is involved on file/directory level. As in "are directory listings cached in the Class version?"
编辑:我特别想知道文件/目录级别是否涉及任何缓存。如“目录列表是否缓存在类版本中?”
AFAIK the following should essentially do the same, but they are not:
AFAIK 以下应该基本上做同样的事情,但它们不是:
getClass().getResource()
getClass().getClassLoader().getResource()
I discovered this when fiddling with some report generation code that creates a new file in WEB-INF/classes/
from an existing file in that directory. When using the method from Class, I could find files that were there at deployment using getClass().getResource()
, but when trying to fetch the newly created file, I recieved a null object. Browsing the directory clearly shows that the new file is there. The filenames were prepended with a forward slash as in "/myFile.txt".
我在处理一些报告生成代码时发现了这一点,这些代码WEB-INF/classes/
从该目录中的现有文件中创建了一个新文件。使用 Class 中的方法时,我可以使用 找到部署getClass().getResource()
时存在的文件,但是在尝试获取新创建的文件时,我收到一个空对象。浏览目录清楚地表明新文件在那里。文件名前面有一个正斜杠,如“/myFile.txt”。
The ClassLoader
version of getResource()
on the other hand did find the generated file. From this experience it seems that there is some kind of caching of the directory listing going on. Am I right, and if so, where is this documented?
另一方面的ClassLoader
版本getResource()
确实找到了生成的文件。从这个经验来看,似乎存在某种目录列表缓存。我是对的,如果是这样,这是在哪里记录的?
From the API docson Class.getResource()
从API 文档开始Class.getResource()
Finds a resource with a given name. The rules for searching resources associated with a given class are implemented by the defining class loader of the class. This method delegates to this object's class loader. If this object was loaded by the bootstrap class loader, the method delegates to ClassLoader.getSystemResource(java.lang.String).
查找具有给定名称的资源。搜索与给定类相关联的资源的规则由类的定义类加载器实现。此方法委托给此对象的类加载器。如果此对象由引导类加载器加载,则该方法委托给 ClassLoader.getSystemResource(java.lang.String)。
To me, this reads "Class.getResource is really calling its own classloader's getResource()". Which would be the same as doing getClass().getClassLoader().getResource()
. But it is obviously not. Could someone please provide me with some illumination into this matter?
对我来说,这读作“Class.getResource 真的在调用它自己的类加载器的 getResource()”。这与执行相同getClass().getClassLoader().getResource()
。但显然不是。有人可以为我提供一些关于这件事的启示吗?
采纳答案by mchlstckl
To answer the question whether there is any caching going on.
回答是否有任何缓存的问题。
I investigated this point further by running a stand-alone Java application that continuously loaded a file from disk using the getResourceAsStream ClassLoader method. I was able to edit the file, and the changes were reflected immediately, i.e., the file was reloaded from disk without caching.
我通过运行一个独立的 Java 应用程序来进一步研究这一点,该应用程序使用 getResourceAsStream ClassLoader 方法从磁盘连续加载文件。我能够编辑该文件,并且更改会立即反映出来,即该文件是从磁盘重新加载而没有缓存。
However:I'm working on a project with several maven modules and web projects that have dependencies on each other. I'm using IntelliJ as my IDE to compile and run the web projects.
但是:我正在处理一个包含多个相互依赖的 Maven 模块和 Web 项目的项目。我使用 IntelliJ 作为我的 IDE 来编译和运行 Web 项目。
I noticed that the above seemed to no longer hold true, the reason being that the file that I was being loaded is now baked into a jar and deployed to the depending web project. I only noticed this after trying to change the file in my target folder, to no avail. This made it seem as though there was caching going on.
我注意到上面的内容似乎不再成立,原因是我正在加载的文件现在被烘焙到一个 jar 中并部署到依赖的 web 项目中。我只是在尝试更改目标文件夹中的文件后才注意到这一点,但无济于事。这使它看起来好像在进行缓存。
回答by Aaron Digulla
The first call searches relative to the .class
file while the latter searches relative to the classpath root.
第一个调用相对于.class
文件进行搜索,而后者相对于类路径根进行搜索。
To debug issues like that, I print the URL:
为了调试这样的问题,我打印了 URL:
System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") );
回答by Bernd Elkemann
Had to look it up in the specs:
不得不在规格中查找它:
Class's getResource() - documentation states the difference:
类的 getResource() - 文档说明了区别:
This method delegates the call to its class loader, after making these changes to the resource name: if the resource name starts with "/", it is unchanged; otherwise, the package name is prepended to the resource name after converting "." to "/". If this object was loaded by the bootstrap loader, the call is delegated to ClassLoader.getSystemResource.
在对资源名称进行这些更改后,此方法将调用委托给其类加载器:如果资源名称以“/”开头,则它保持不变;否则,在转换“.”后,包名将被添加到资源名之前。到 ”/”。如果此对象由引导加载程序加载,则调用将委托给 ClassLoader.getSystemResource。
回答by Jon Skeet
Class.getResource
can take a "relative" resource name, which is treated relative to the class's package. Alternatively you can specify an "absolute" resource name by using a leading slash. Classloader resource paths are always deemed to be absolute.
Class.getResource
可以采用“相对”资源名称,该名称相对于类的包进行处理。或者,您可以使用前导斜杠指定“绝对”资源名称。类加载器资源路径总是被认为是绝对的。
So the following are basically equivalent:
所以以下基本上是等价的:
foo.bar.Baz.class.getResource("xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("foo/bar/xyz.txt");
And so are these (but they're different from the above):
这些也是(但它们与上述不同):
foo.bar.Baz.class.getResource("/data/xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("data/xyz.txt");
回答by Tim Büthe
All these answers around here, as well as the answers in this question, suggest that loading absolute URLs, like "/foo/bar.properties" treated the same by class.getResourceAsStream(String)
and class.getClassLoader().getResourceAsStream(String)
. This is NOT the case, at least not in my Tomcat configuration/version (currently 7.0.40).
这里的所有这些答案,以及这个问题中的答案,都表明加载绝对 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!
Sorry, I have absolutely no satisfying explanation, but I guess that tomcat does dirty tricks and his black magic with the classloaders and cause the difference. I always used class.getResourceAsStream(String)
in the past and haven't had any problems.
抱歉,我绝对没有令人满意的解释,但我猜想 tomcat 对类加载器做了肮脏的把戏和他的黑魔法,并导致了差异。我class.getResourceAsStream(String)
过去一直使用,没有任何问题。
PS: I also posted this over here
PS:我也贴在这里
回答by Kevin Lee
I tried reading from input1.txt which was inside one of my packages together with the class which was trying to read it.
我尝试从我的一个包中的 input1.txt 以及试图读取它的类中读取。
The following works:
以下工作:
String fileName = FileTransferClient.class.getResource("input1.txt").getPath();
System.out.println(fileName);
BufferedReader bufferedTextIn = new BufferedReader(new FileReader(fileName));
The most important part was to call getPath()
if you want the correct path name in String format. DO NOT USE toString()
because it will add some extra formatting text which will TOTALLY MESS UP the fileName (you can try it and see the print out).
最重要的部分是调用getPath()
是否需要字符串格式的正确路径名。不要使用,toString()
因为它会添加一些额外的格式文本,这会完全弄乱文件名(你可以试试看打印出来)。
Spent 2 hours debugging this... :(
花了 2 个小时调试这个... :(
回答by lwpro2
Class.getResources
would retrieve the resource by the classloader which load the object. While ClassLoader.getResource
would retrieve the resource using the classloader specified.
Class.getResources
将通过加载对象的类加载器检索资源。WhileClassLoader.getResource
将使用指定的类加载器检索资源。