1. 概述
在这个简短的教程中,我们将探讨Class.getResource()
和ClassLoader.getResource()
方法之间的差异。
2. getResource()
方法
我们可以使用Class
或ClassLoader
实例的getResource()
方法来查找具有给定名称的资源。资源被认为是数据,例如图片、文本、音频等。作为路径分隔符,应始终使用斜杠("/")。
该方法返回一个用于读取资源的URL对象,如果找不到资源或调用者没有权限获取资源,则返回null
。
3. Class.getResource()
现在,让我们看看如何使用Class
对象获取资源。在使用Class
对象定位资源时,可以传递绝对路径或相对路径。
与给定类关联的资源搜索规则由类加载器实现。
查找资源的过程将委托给类对象的类加载器。换句话说,Class
实例上的getResouce()
方法最终会调用ClassLoader
的getResouce()
方法。
在委托之前,会根据给定资源名生成绝对资源名。创建绝对资源名时,将使用以下算法:
- 如果资源名以斜杠开头("/"),则表示资源名是绝对的。绝对资源名会去掉开头的斜杠,并直接传递给适当的
ClassLoader
方法来定位资源。 - 如果提供的资源名不以斜杠开头,它将被视为相对于类的包。相对名称首先转换为绝对路径,然后传递给
ClassLoader
方法。
假设我们在com/baeldung/resource
目录中定义了example.txt
资源,并且在com.baeldung.resource
包中定义了ClassGetResourceExample
类。现在,我们可以使用绝对路径获取资源:
void givenAbsoluteResourcePath_whenGetResource_thenReturnResource() {
URL resourceAbsolutePath = ClassGetResourceExample.class
.getResource("/com/baeldung/resource/example.txt");
Assertions.assertNotNull(resourceAbsolutePath);
}
当使用Class.getResource()
时,绝对资源路径应始终以斜杠开头。
此外,由于我们的资源位于类的同一包内,我们也可以使用相对路径获取它:
void givenRelativeResourcePath_whenGetResource_thenReturnResource() {
URL resourceRelativePath = ClassGetResourceExample.class.getResource("example.txt");
Assertions.assertNotNull(resourceRelativePath);
}
但是,请注意,只有当资源位于类的同一包内时,才能使用相对路径获取资源。否则,将得到null
作为值。
4. ClassLoader.getResource()
顾名思义,ClassLoader
表示负责加载类的类。每个Class
实例都包含对其ClassLoader
的引用。
ClassLoader
类使用委托模式来搜索类和资源。此外,每个ClassLoader
实例都有一个关联的父ClassLoader
。
在被要求查找资源时,ClassLoader
实例首先将其搜索委托给父ClassLoader
,然后再尝试自己查找资源。
如果找不到父ClassLoader
,则会搜索虚拟机内置的ClassLoader
(称为引导类加载器)的路径。引导类加载器没有父加载器,但可能作为ClassLoader
实例的父加载器。
如果前面的搜索失败,方法将调用findResource()
方法来查找资源。
指定的资源名称始终被视为绝对的。值得注意的是,Java从classpath加载资源。
使用绝对路径和ClassLoader
实例获取资源:
void givenAbsoluteResourcePath_whenGetResource_thenReturnResource() {
URL resourceAbsolutePath = ClassLoaderGetResourceExample.class.getClassLoader()
.getResource("com/baeldung/resource/example.txt");
Assertions.assertNotNull(resourceAbsolutePath);
}
当我们调用ClassLoader.getResource()
时,定义绝对路径时应省略开头的斜杠。
使用ClassLoader
实例,我们无法使用相对路径获取资源:
void givenRelativeResourcePath_whenGetResource_thenReturnNull() {
URL resourceRelativePath = ClassLoaderGetResourceExample.class.getClassLoader()
.getResource("example.txt");
Assertions.assertNull(resourceRelativePath);
}
上述测试显示,方法的结果是null
值。
5. 总结
这个简短的教程解释了从Class
和ClassLoader
实例调用getResource()
方法的区别。总结来说,使用Class
实例调用方法时,可以传递相对或绝对资源路径,而使用ClassLoader
调用时只能使用绝对路径。
如往常一样,代码可在GitHub上找到。