我使用Eclipse开发了一个Java项目,需要加载一些图像并显示它们。起初,我这样加载它们:
InputStream stream = MyClass.class.getClass().getResourceAsStream("/resources/ui/icons/" + name);
Image img = ImageIO.read(stream).getScaledInstance(size.width, size.height, Image.SCALE_SMOOTH);
无论我是从Eclipse运行还是从可执行jar运行它,这都运行良好。但是我最近买了一台新笔记本电脑,当我试图在新机器上运行它时,罐子就不会运行了; stream
总是证明是null
。但是,当我从Eclipse内部运行时,不会发生此问题。
最后,经过一些实验,我改变了代码,直接在getResourceAsStream()
上调用MyClass.class
而不调用getClass()
:
InputStream stream = MyClass.class.getResourceAsStream("/resources/ui/icons/" + name);
Image img = ImageIO.read(stream).getScaledInstance(size.width, size.height, Image.SCALE_SMOOTH);
出于某种原因,它有效。我的新笔记本电脑具有与旧笔记本电脑相同的操作系统(Windows 10)和其他设置,但它运行Eclipse Photon而不是Oxygen。
那么,两种加载资源的方式有什么区别? (我听说这是关于ClassLoaders的东西,但我记不起确切的话。)为什么切换到新机器会打破第一个?即使是第二个,我正确地做到了吗?
MyClass.class返回表示类MyClass
的java.lang.Class实例。调用.getClass返回表示java.lang.Class
本身的Class实例,并在THAT上调用getResourceAsStream
将尝试在java.base中找到资源(java.lang.Class
所在的位置)。一般来说,不是你想要的。换句话说,你的第一个例子与java.lang.Class.class.getResourceAsStream(...)
相同。
第二个例子是正确的方法。
第一件事在一些地方起作用的原因是因为它完全取决于如何在Java SE 8及更早版本中指定Class.getResourceXXX。 Java SE 9中的规范已更改,以处理Class是命名模块的类。