1. 概述

在这个简短的教程中,我们将探讨Class.getResource()ClassLoader.getResource()方法之间的差异。

2. getResource()方法

我们可以使用ClassClassLoader实例的getResource()方法来查找具有给定名称的资源。资源被认为是数据,例如图片、文本、音频等。作为路径分隔符,应始终使用斜杠("/")。

该方法返回一个用于读取资源的URL对象,如果找不到资源或调用者没有权限获取资源,则返回null

3. Class.getResource()

现在,让我们看看如何使用Class对象获取资源。在使用Class对象定位资源时,可以传递绝对路径或相对路径。

与给定类关联的资源搜索规则由类加载器实现。

查找资源的过程将委托给类对象的类加载器。换句话说,Class实例上的getResouce()方法最终会调用ClassLoadergetResouce()方法。

在委托之前,会根据给定资源名生成绝对资源名。创建绝对资源名时,将使用以下算法:

  • 如果资源名以斜杠开头("/"),则表示资源名是绝对的。绝对资源名会去掉开头的斜杠,并直接传递给适当的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. 总结

这个简短的教程解释了从ClassClassLoader实例调用getResource()方法的区别。总结来说,使用Class实例调用方法时,可以传递相对或绝对资源路径,而使用ClassLoader调用时只能使用绝对路径。

如往常一样,代码可在GitHub上找到。