Class#getResource与ClassLoader#getResource分析

原创 2016年08月29日 11:32:36
  • Class#getResource方法的参数path可以与以'/'开头的绝对路径或是不以'/'开头的相对路径,当以'/'开头时,会从classpath路径下获取资源,当不以'/'开头时,则从该类所在的包下获取资源,xxx.class.getResource() 即xxx.class类所在包。
  • 而ClassLoader#getResource方法的参数却不能以'/'开头,其是从classpath下面获取资源。

来看看下面代码的结果

package com.jdk.resource;
public class Resource {
     public static void main(String[] args) throws Exception {
            System.out.println(Resource.class.getResource(""));
            System.out.println(Resource.class.getResource("/"));
            System.out.println(Resource.class.getClassLoader().getResource(""));
            System.out.println(Resource.class.getClassLoader().getResource("/"));
        }
}

结果:

file:/D:/workspace/JDKCore/bin/com/jdk/resource/
file:/D:/workspace/JDKCore/bin/
file:/D:/workspace/JDKCore/bin/
null

可以看到Resource.class.getResource("")得到的路径classpath下Resource 类所在包,而Resource.class.getResource("/")为classpath根路径;而Resource.class.getClassLoader().getResource("")同样为classpath根路径,Resource.class.getClassLoader().getResource("/")则为空。 下面来看看Class#getResource方法的源码

public java.net.URL getResource(String name) {
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResource(name);
        }
        return cl.getResource(name);
    }

从 cl.getResource(name)一行可以看出,Class#getResource方法最终还是调用了CalssLoader#getResource方法。再来看看name = resolveName(name)的实现,做了什么处理,其调用了Class类的resolveName方法

private String resolveName(String name) {
        if (name == null) {
            return name;
        }
        if (!name.startsWith("/")) {
            Class<?> c = this;
            while (c.isArray()) {
                c = c.getComponentType();
            }
            String baseName = c.getName();
            int index = baseName.lastIndexOf('.');
            if (index != -1) {
                name = baseName.substring(0, index).replace('.', '/')
                    +"/"+name;
            }
        } else {
            name = name.substring(1);
        }
        return name;
    }

可以看出,resolveName方法的目的是当参数name以'/'开头就将'/'去除再返回,而当不以'/'开头则根据这个类对应的带包名全称变换成具体的路径名,如com.jdk.resource替换成com/jdk/resource。

现在应该明白最开始那个Resource 类中main方法的结果,实际上Class#getResource方法是去调CalssLoader#getResource的方法,只是在调用时会去判断是从相对路径还是绝对路径获取资源。不过api是有一点点坑Class#getResource以'/'开头与ClassLoader#getResource相同,再记住ClassLoader#getResource不能以'/'开头就行了。

有了前面这个Classr#getResource与ClassLoader#getResource的对比,Class#getResourceAsStream与ClassLoader#getResourceAsStream其实也就ok了。

Class#getResourceAsStream源码:

public InputStream getResourceAsStream(String name) {
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResourceAsStream(name);
        }
        return cl.getResourceAsStream(name);
    }

ClassLoader#getResourceAsStream源码:

public InputStream getResourceAsStream(String name) {
        URL url = getResource(name);
        try {
            return url != null ? url.openStream() : null;
        } catch (IOException e) {
            return null;
        }
    }

所以,可以用下面三种方式得到资源

  1. 利用Class#getResourceAsStream方法根据绝对路径从classpath下面得到,参数path以'/'开头
  2. 利用Class#getResourceAsStream方法根据类所处包的相对路径得到,参数path不能以'/'开头
  3. 利用ClassLoader#getResourceAsStream方法根绝对路径从classpath下面得到,参数path不能以'/'开头

在com.jdk.resource目录下创建一个test.properties文件,可以用以下三种方式得到

package com.jdk.resource;
public class Resource {
     public static void main(String[] args) throws Exception {
            //第一种方式
            System.out.println(Resource.class.getResourceAsStream("test.properties"));
            //第二种方式
           System.out.println(Resource.class.getResourceAsStream("/com/jdk/resource/test.properties"));
            //第三种方式
    System.out.println(Resource.class.getClassLoader().getResourceAsStream("com/jdk/resource/test.properties"));
        }
}

结果:

java.io.BufferedInputStream@659e0bfd
java.io.BufferedInputStream@2a139a55
java.io.BufferedInputStream@15db9742

这对查看,Spring Resource 接口的实现ClassPathResource类getInputStream方法有一定帮助

public InputStream getInputStream() throws IOException {
        InputStream is;
        if (this.clazz != null) {
            is = this.clazz.getResourceAsStream(this.path);
        }
        else if (this.classLoader != null) {
            is = this.classLoader.getResourceAsStream(this.path);
        }
        else {
            is = ClassLoader.getSystemResourceAsStream(this.path);
        }
        if (is == null) {
            throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
        }
        return is;
    }
版权声明:本文为博主原创文章,未经博主允许不得转载。

OO设计与分析总结之一

OO设计与分析总结之一
  • syf88888888
  • syf88888888
  • 2016年12月05日 21:15
  • 209

计算机算法设计与分析(第4版) 王晓东 著 2012.2 笔记(这本书还不错,偏实用、有难度)

计算机算法设计与分析(第4版) 目录 1 算法概述2 递归与分治策略3 动态规划4 贪心算法5 回溯法6 分支限界法7 随机化算法8 线性规划与网络流 ...
  • cteng
  • cteng
  • 2014年10月07日 22:54
  • 2847

《计算机算法设计与分析》题目汇总

Github源码地址:https://github.com/hlk-1135/Data-Structures-and-Algorithms递归与分治: 电路布线问题 有重复元素的排列问题 集合划分问题...
  • HLK_1135
  • HLK_1135
  • 2017年01月02日 10:11
  • 1564

算法设计与分析——基础知识

算分第1章
  • Victor__2015
  • Victor__2015
  • 2017年01月18日 22:48
  • 234

图像处理、分析与机器视觉 (4th).pdf 免费下载

下载地址: 图像处理、分析与机器视觉 (4th).pdf
  • jiongyi1
  • jiongyi1
  • 2018年01月09日 19:14
  • 293

算法设计与分析基础

To All Of You:一个人在接受科技教育时能得到的最珍贵的收获是能够终身受用的通用智能工具。在讨论算法的书籍中,一般会采用两种方案中的一种:1.第一种方案是按照问题的类型对算法进行分类。这类教...
  • he_world
  • he_world
  • 2016年12月21日 11:59
  • 1202

《算法设计与分析基础 第二版》pdf

下载地址:网盘下载 内容简介 编辑   国外经典教材·计算机科学与技术:该书作者基于教学经验,开发了一套对算法进行分类的新方法。内容包括算法效率分析基础、蛮力...
  • cf406061841
  • cf406061841
  • 2017年05月27日 19:02
  • 531

算法设计与分析期末上机考试总结

A约翰的零花钱 上机考试(2016) 时间限制2000ms内存限制65536KB 题目描述 约翰要对自己的花费进行规划。他首先计算得到了后面N(1 输入格式 第一行为两个数字N M,接下来有N行,每行...
  • qq_32400847
  • qq_32400847
  • 2016年07月02日 18:37
  • 1056

计算机算法设计与分析(1)--算法概述

基本说明计算机算法设计与分析系列为本人在计算机算法设计与分析的学习阶段的个人学习心得笔记。 由于本人能力有限,因此其中不乏有缺漏之处,欢迎批评指正。该笔记参考书籍为(third edition) 和...
  • williamyi96
  • williamyi96
  • 2017年03月04日 18:45
  • 1203

算法设计与分析——N后问题(C++实现)

#include   #include      class Queen   {       friend int nQueen(int);    private:       bool Place(...
  • bird5233
  • bird5233
  • 2010年11月21日 16:55
  • 266
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Class#getResource与ClassLoader#getResource分析
举报原因:
原因补充:

(最多只允许输入30个字)