Loading resources from files is generally a bad idea. Files are always
either relative to the current directory of the application or absolute and
therefore platform-dependant. If the application is expected to work on
any operating system without a change the use of File
for resources
should be avoided.
public File(String pathname)
pathname
is resolved relative to the current application directory if
it's not an absolute path already.public File(String parent, String child)
parent
was obtained in a platform independant way e.g. by calling
System.getProperty(String)
with argument "java.io.tmpdir"
for temporary files or "user.home"
for application settings.
java.lang.ClassLoader
or java.lang.Class
By using the methods getResource
and getResourceAsStream
of
java.lang.ClassLoader
or java.lang.Class
the resource locations are
at least platform independant. They can (and should) be contained in JAR files which translates
into faster resolution and less disk space usage.
Resources obtained by the ClassLoader
(directly or
indirectly by Class
) are never locale specific like
ResourceBundle
-resources (explained below).
A (quite unobvious) drawback of Class.getResource
is that the apparent
usage results in an inheritance unsafe class under certain circumstances.
This is probably best explained by an example:
package foobar;
public class Foo
{
public void someMethod()
{
[..]
URL resourceUrl = getClass().getResource("myResource.png");
[..]
}
}
Looks quite right, doesn't it? Well, it isn't. Instead it contains a major bug!
Because Foo
is public
and not final
it's possible
to extend it.
package your.customer;
public class MyFoo extends foobar.Foo
{
public void anotherMethod()
{
[..]
someMethod();
[..]
}
}
If your customer calls someMethod()
the class MyFoo
won't
be able to find the resource because it is searched for relative to the
package your.customer
(getClass()
in someMethod()
will, correctly but very unlikely expected, return
your.customer.MyFoo.class
instead of foobar.Foo.class
).
The correct way to implement class Foo
in an inheritance safe manner
would look like this:
package foobar;
public class Foo
{
public void someMethod()
{
[..]
URL resourceUrl = Foo.class.getResource("myResource.png");
[..]
}
}
That way someMethod()
will still search relative to the package foobar
even
if called on an extending class in a different package.
java.util.ResourceBundle
The obvious solution.