Loading resources using getClass().getResource()

2019-01-02 16:17发布

I am trying to load an image to use as an icon in my application. The appropriate method according to this tutorial is:

protected ImageIcon createImageIcon(String path, String description) 
{
    java.net.URL imgURL = getClass().getResource(path);
    if (imgURL != null) {
        return new ImageIcon(imgURL, description);
    } else {
        System.err.println("Couldn't find file: " + path);
        return null;
    }
}

So, I placed the location of the file, and passed it as a parameter to this function. This didn't work, i.e. imgURL was null. When I tried creating the ImageIcon by passing in the path explicitly:

ImageIcon icon  = new ImageIcon(path,"My Icon Image");

It worked great! So the application can pick up the image from an explicitly defined path, but didn't pick up the image using getResources(). In both cases, the value of the path variable is the same. Why wouldn't it work? How are resources found by the class loader?

Thanks.

标签: java swing
4条回答
梦寄多情
2楼-- · 2019-01-02 16:23

getResource by example:

package szb.testGetResource;
public class TestGetResource {
    private void testIt() {
        System.out.println("test1: "+TestGetResource.class.getResource("test.css"));
        System.out.println("test2: "+getClass().getResource("test.css"));
    }
    public static void main(String[] args) {
        new TestGetResource().testIt();
    }
}

enter image description here

output:

test1: file:/home/szb/projects/test/bin/szb/testGetResource/test.css
test2: file:/home/szb/projects/test/bin/szb/testGetResource/test.css
查看更多
其实,你不懂
3楼-- · 2019-01-02 16:24

You can request a path in this format:

/package/path/to/the/resource.ext

Even the bytes for creating the classes in memory are found this way:

my.Class -> /my/Class.class

and getResource will give you a URL which can be used to retrieve an InputStream.

But... I'd recommend using directly getClass().getResourceAsStream(...) with the same argument, because it returns directly the InputStream and don't have to worry about creating a (probably complex) URL object that has to know how to create the InputStream.

In short: try using getResourceAsStream and some constructor of ImageIcon that uses an InputStream as an argument.

Classloaders

Be careful if your app has many classloaders. If you have a simple standalone application (no servers or complex things) you shouldn't worry. I don't think it's the case provided ImageIcon was capable of finding it.

Edit: classpath

getResource is—as mattb says—for loading resources from the classpath (from your .jar or classpath directory). If you are bundling an app it's nice to have altogether, so you could include the icon file inside the jar of your app and obtain it this way.

查看更多
无与为乐者.
4楼-- · 2019-01-02 16:25

getClass().getResource(path) loads resources from the classpath, not from a filesystem path.

查看更多
流年柔荑漫光年
5楼-- · 2019-01-02 16:31

As a noobie I was confused by this until I realized that the so called "path" is the path relative to the MyClass.class file in the file system and not the MyClass.java file. My IDE copies the resources (like xx.jpg, xx.xml) to a directory local to the MyClass.class. For example, inside a pkg directory called "target/classes/pkg. The class-file location may be different for different IDE's and depending on how the build is structured for your application. You should first explore the file system and find the location of the MyClass.class file and the copied location of the associated resource you are seeking to extract. Then determine the path relative to the MyClass.class file and write that as a string value with "dots" and "slashes".

For example, here is how I make an app1.fxml file available to my javafx application where the relevant "MyClass.class" is implicitly "Main.class". The Main.java file is where this line of resource-calling code is contained. In my specific case the resources are copied to a location at the same level as the enclosing package folder. That is: /target/classes/pkg/Main.class and /target/classes/app1.fxml. So paraphrasing...the relative reference "../app1.fxml" is "start from Main.class, go up one directory level, now you can see the resource".

FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("../app1.fxml"));

Note that in this relative-path string "../app1.fxml", the first two dots reference the directory enclosing Main.class and the single "." indicates a file extension to follow. After these details become second nature, you will forget why it was confusing.

查看更多
登录 后发表回答