在Java中加载资源的首选方式

时间:2010-10-05 08:28:00

标签: java resources

我想知道在Java中加载资源的最佳方法:

  • this.getClass().getResource() (or getResourceAsStream())
  • Thread.currentThread().getContextClassLoader().getResource(name)
  • System.class.getResource(name)

5 个答案:

答案 0 :(得分:129)

根据您的需要制定解决方案......

getResource / getResourceAsStream()会从调用的类中获取两件事......

  1. 类加载器
  2. 起始位置
  3. 所以,如果你这样做

    this.getClass().getResource("foo.txt");
    

    它将尝试从与“this”类相同的包中加载foo.txt,并使用“this”类的类加载器。如果你在前面放了一个“/”,那么你绝对是引用资源的。

    this.getClass().getResource("/x/y/z/foo.txt")
    

    将从“this”的类加载器和x.y.z包中加载资源(它需要与该包中的类位于同一目录中)。

    Thread.currentThread().getContextClassLoader().getResource(name)
    

    将使用上下文类加载器加载,但不会根据任何包解析名称(必须绝对引用)

    System.class.getResource(name)
    

    将使用系统类加载器加载资源(它必须完全引用,因为您将无法将任何内容放入java.lang包(System的包)。

    请看一下来源。还表示getResourceAsStream只是在getResource返回的URL上调用“openStream”并返回它。

答案 1 :(得分:13)

嗯,这部分取决于你在派生类中实际时想要发生什么。

例如,假设SuperClass位于A.jar中,SubClass位于B.jar中,并且您正在SuperClass中声明的实例方法中执行代码,但其中this 1}}是指SubClass的一个实例。如果您使用this.getClass().getResource(),它将相对于B.jar中的SubClass。我怀疑通常不是所需要的。

就我个人而言,我最常使用Foo.class.getResourceAsStream(name) - 如果你已经知道你所追求的资源的名称,并且你确定它相对于Foo的位置,那就是最有力的方式IMO。

当然有时候你想要的是什么:根据每个案例的优点来判断。它只是“我知道这个资源与这个类捆绑在一起”是我遇到过的最常见的一个。

答案 2 :(得分:9)

我搜索三个地方,如下所示。欢迎评论。

public URL getResource(String resource){

    URL url ;

    //Try with the Thread Context Loader. 
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    if(classLoader != null){
        url = classLoader.getResource(resource);
        if(url != null){
            return url;
        }
    }

    //Let's now try with the classloader that loaded this class.
    classLoader = Loader.class.getClassLoader();
    if(classLoader != null){
        url = classLoader.getResource(resource);
        if(url != null){
            return url;
        }
    }

    //Last ditch attempt. Get the resource from the classpath.
    return ClassLoader.getSystemResource(resource);
}

答案 3 :(得分:2)

我知道另一个答案真的很晚,但我只想分享最后帮助我的东西。它还将从文件系统的绝对路径(不仅是类路径)加载资源/文件。

public class ResourceLoader {

    public static URL getResource(String resource) {
        final List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
        classLoaders.add(Thread.currentThread().getContextClassLoader());
        classLoaders.add(ResourceLoader.class.getClassLoader());

        for (ClassLoader classLoader : classLoaders) {
            final URL url = getResourceWith(classLoader, resource);
            if (url != null) {
                return url;
            }
        }

        final URL systemResource = ClassLoader.getSystemResource(resource);
        if (systemResource != null) {
            return systemResource;
        } else {
            try {
                return new File(resource).toURI().toURL();
            } catch (MalformedURLException e) {
                return null;
            }
        }
    }

    private static URL getResourceWith(ClassLoader classLoader, String resource) {
        if (classLoader != null) {
            return classLoader.getResource(resource);
        }
        return null;
    }

}

答案 4 :(得分:-1)

我尝试了很多上面建议的方法和功能,但它们在我的项目中没有用。无论如何,我找到了解决方案,这里是:

try {
    InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
    img = ImageIO.read(path);
} catch (IOException e) {
    e.printStackTrace();
}