你真正需要的是这样调用:
ImageUtils.class.getResourceAsStream("commonImg.png");
这里ImageUtils.class
表达式是一个类型为java.lang.Class<ImageUtils>
的对象,它代表了你的ImageUtils
类。这个对象有一个getResourceAsStream
方法可以直接用来获取资源流。
错误的示范是这样:
ImageUtils.class.getClass()
因为ImageUtils.class
已经返回了一个表示ImageUtils
类的java.lang.Class
实例,再对这个实例调用getClass()
方法实际上是得到了代表java.lang.Class
自身的类实例,这显然不是你想要的结果。
正确的做法是直接使用ImageUtils.class.getResourceAsStream
来获取资源。
关于尝试获取资源路径的问题,资源并不是文件系统中的目录,你不能像访问文件系统那样去请求目录或者根路径。如果你尝试这样做,在某些特定的类路径、加载器或JVM组合下可能能工作,但在其他情况下则不行。这是非常糟糕且不可预测的错误,最好的做法是避免尝试这类操作。
如果需要列出“目录”中的所有条目,使用类加载器抽象是做不到的。这时可以采用SPI(服务提供者接口)的方式:编译时(可以通过注解处理器、构建系统插件或手动维护文件)创建一个带有已知名称的文件来列出列表中的每一项,然后通过getResourceAsStream
加载这个文件,读取并进一步根据内容加载相关资源,从而间接实现了“列出所有内容”的功能。Java自身就采用了这种机制,其中读取列表的部分由ServiceLoader
类提供支持。
你提到的方法不起作用,可能是因为没有正确处理资源路径的相对性。j.l.Class
实例上的getResource
和getResourceAsStream
方法查找资源的路径是相对于类所在的包的。例如,如果ImageUtils
类声明在package com.foo.hhrzc;
下,那么getResource("commonImg.png")
会查找路径为/com/foo/hhrzc/commonImg.png
的资源条目。
要从类路径的根开始查找,只需在资源名前加上斜杠,即.getResourceAsStream("/commonImg.png")
,这样就会在包含ImageUtils.class
的相同jar文件中寻找名为/commonImg.png
的条目。
需要注意的几点是:
- 文件名中不能有多个点,因为某些原因这会导致问题。
ClassLoader
实例也有这些getResource
和getResourceAsStream
方法,但它们默认就是从根开始查找的,而且如果路径以斜杠开头通常会失败。这导致了一些混淆:如果你想从根开始查找,对于j.l.Class.getResource
需要在资源名前加斜杠,而对于j.l.ClassLoader
的这些方法则不应该加斜杠。通常来说,直接在类上调用这些方法比在类加载器上调用更为简单、通用且不易出错。最标准、最简洁、最通用的加载已知资源的方式是使用语法:SomeClass.class.getResource("resourceName")
,这里的resourceName
如果是绝对路径,应当以斜杠开头。