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

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

我认为下面这些应该做同样的事情,但它们不是:

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

我在摆弄一些报告生成代码时发现了这一点,这些代码从WEB-INF/classes/目录中的现有文件创建了一个新文件。当使用来自Class的方法时,我可以使用getClass(). getresource()找到部署时存在的文件,但当试图获取新创建的文件时,我收到了一个空对象。浏览目录会清楚地显示新文件在那里。文件名以斜杠开头,如"/myFile.txt"。

另一方面,getResource()的ClassLoader版本确实找到了生成的文件。从这个经验来看,似乎有某种目录列表的缓存正在进行。我说得对吗?如果是的话,这在哪里有记录?

来自Class.getResource()上的API文档

寻找资源 有一个名字。的规则 查找关联的资源 类实现 定义类的类装入器。 此方法委托给该对象的方法 类装入器。如果这个对象是 由引导类装入器装入, 方法委托给 ClassLoader.getSystemResource(以)。

对我来说,这就是“阶级”。getResource实际上是调用它自己的类加载器的getResource()”。这将与执行getClass(). getclassloader (). getresource()相同。但事实显然并非如此。有人能给我一些关于这件事的说明吗?


当前回答

我试着从input1.txt中读取,它在我的一个包中,和试图读取它的类一起。

以下工作:

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

System.out.println(fileName);

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

最重要的部分是调用getPath(),如果您想要字符串格式的正确路径名。不要使用toString(),因为它会添加一些额外的格式文本,这将完全混乱的文件名(你可以尝试一下,看看打印出来)。

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

其他回答

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

另一种更有效的方法是使用@Value

@Value("classpath:sss.json")
private Resource resource;

然后你就可以这样获取文件了

File file = resource.getFile();

我试着从input1.txt中读取,它在我的一个包中,和试图读取它的类一起。

以下工作:

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

System.out.println(fileName);

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

最重要的部分是调用getPath(),如果您想要字符串格式的正确路径名。不要使用toString(),因为它会添加一些额外的格式文本,这将完全混乱的文件名(你可以尝试一下,看看打印出来)。

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

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

自Java 9以来,在模块路径上运行ClassLoader#getResource时存在一个陷阱。因此,我永远不会在新代码中使用ClassLoader#getResource。

如果您的代码在一个命名模块中,并且您使用了ClassLoader#getResource,那么即使资源在同一个模块中,您的代码也可能无法检索到资源。这是非常令人惊讶的行为。

我自己经历过,对Class#getResource和ClassLoader#getResource之间的差异感到非常惊讶。然而,它完全是根据javadoc指定的行为:

此外,除了资源名称以".class"结尾的特殊情况外,当包被无条件打开时,此方法只会在命名模块的包中找到资源(即使此方法的调用者与资源在同一个模块中)。 Javadoc(重点矿山)