getClass().getResource()与getClassLoader().getResource()的区别

getClass().getResource()与getClassLoader().getResource()的区别

简介

项目中我们经常要获取资源路径,我们会使用类名.getClass().getResource()和getClassLoader().getResource()。这两个经常乱用,用着用着就迷了,
有些时候路径获取的乱七八糟,为什么没有获取到,或是获取到的不对,我们来看下,我们随便定义一个类,然后对比下输出的路径。
而且,windows下的路径和linux路径规则,大不一样,很有可能在windows下测试好好的,然后改成linux下的路径,放到服务器上就出问题了。

测试结果

测试项目的路径test/java下:

在这里插入图片描述

package my;

import my.son.Son;

public class Father {

    protected void ask(){
        System.out.println("I am Father");
    }

    public void  ask2(){
        ask();
    }


    public static void main(String[] args) {

        Father father = new Father();

        System.out.println(father.getClass().getResource(""));

        System.out.println(father.getClass().getResource("/"));

        System.out.println(father.getClass().getClassLoader().getResource(""));

        System.out.println(father.getClass().getClassLoader().getResource("/"));

    }
}    

在包名my下,我们新建一个类Father,然后查看运行结果。
在这里插入图片描述

我们看到第二个和第三个路径一样,第一个路径多了一个包名,最后一个是null没有获取到路径。
#源码分析
我们来看下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);
    }

这里最终调用的还是ClassLoader.getResource()方法,但是在调用之前,有个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;
    }

这段代码的逻辑是处理name中的路径:
1.如果是绝对路径(也就是以“/”开头),那么就删除“/”,这里要注意了,在windows下绝对路径是有盘符概念的,
但是在linux或mac下,绝对路径就是“/”开头的,
所以如果在windows下测试没有问题,那么在linux下可能会有问题。

2.如果不是绝对路径,那么就获取包名,添加上包名(class的类对象的包名,列子中是Father的包名)。

Resources资源目录

在这里插入图片描述

我们在项目Resources资源目录下,创建一个123.txt,来看下程序寻找路径的结果。
代码如下

System.out.println(father.getClass().getResource("123.txt"));
System.out.println(father.getClass().getResource("/123.txt"));
System.out.println(father.getClass().getClassLoader().getResource("123.txt"));
System.out.println(father.getClass().getClassLoader().getResource("/123.txt"));

结果如下

在这里插入图片描述

  1. father.getClass().getResource(“123.txt”)加上了Father的包名,实际上找寻的是my/123.txt,当然找不到。
  2. System.out.println(father.getClass().getResource("/123.txt"))为什么能找到,因为“/123.txt”中的“/”被当作绝对路径处理,被删除了,最终找寻的是“123.txt”。
  3. father.getClass().getClassLoader().getResource(“123.txt”)找寻的就是123.txt,所以能找到,不解释。
  4. father.getClass().getClassLoader().getResource("/123.txt")找寻的是/123.txt,所以找不到。

最终的问题

为什么在Resources目录下,能够找寻的到?

System.out.println("sun.boot.class.path----->"+System.getProperty("sun.boot.class.path"));
System.out.println("java.ext.dirs----->"+System.getProperty("java.ext.dirs"));
System.out.println("java.class.path----->"+System.getProperty("java.class.path"));

上面三个是三个类加载器的加载路径,Resources的路径包含在“java.class.path”下,可以打印看看。

总结

1.项目中不要使用getClass().getResource,因为有绝对路径的转化及包名的问题。
2.最好使用getClassLoader().getResource,没有以上的问题,不过不建议使用绝对路径。
3.如果getClassLoader().getResource加载不到,请检查系统属性java.class.path是否包含路径。

更多内容请看个人博客:请点击此处

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值