getResource 的作用

getResourceClass类中的一个方法
作用:配置文件的读取

Class 的概念

首先我们得知道,在new一个对象的时候,会在java堆中生成一个代表这个类的java.lang.Class对象,(Class 对象不能主动创建,只能获取)作为该类的数据访问入口
那么我们如何使用对应的Class对象呢?
三种方法 ,先看看我的目录结构

Resource.class     //直接使用类名.class
Class.forName("zhang.Resource")  //包名.类名   需要捕获异常
new Resource().getClass()    //先获取一个对象  再调用对象的 getClass()方法

现在我们写6个语句,前3个没/ ,后3个有/ (强烈建议自己试一试)

public class Resource {public static void main(String[] args) throws IOException {System.out.println("------------------------------getResource(\"\")测试---------------------");// 1 返回 target/classes/packageSystem.out.println(Resource.class.getResource(""));// 2 同级(编译路径)下,是否存在对应文件,存在则返回该地址System.out.println(Resource.class.getResource("Resource.class"));// 3 不存在,返回 nullSystem.out.println(Resource.class.getResource("NoResource.class") + "\n\n");System.out.println("------------------------------getResource(\"/\")测试---------------------");// 4 返回 target/classes/System.out.println(Resource.class.getResource("/"));// 5 target/classes/ 目录下不存在 Resource.classSystem.out.println(Resource.class.getResource("/Resource.class"));// 6 target/classes/ 目录下存在 cn/zhangSystem.out.println(Resource.class.getResource("/cn/zhang"));}
}

结果如下,返回的地址都是绝对地址

------------------------------getResource("")测试---------------------
file:/E:/zy-source-learn/spring-family/springboot3-source-learn/target/classes/cn/zhang/springboot3sourcelearn/demo/
file:/E:/zy-source-learn/spring-family/springboot3-source-learn/target/classes/cn/zhang/springboot3sourcelearn/demo/Resource.class
null------------------------------getResource("/")测试---------------------
file:/E:/zy-source-learn/spring-family/springboot3-source-learn/target/classes/
null
file:/E:/zy-source-learn/spring-family/springboot3-source-learn/target/classes/cn/zhang

区别如下

  • /target/classes/package
  • /target/classes/

/,有点类似于 linux 中的 / —— 根路径 (而无 / 相当于相对路径)

getResource 源码分析

现在我们来分析:按ctrl + 鼠标左键,点进去查看源码

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);
}

对传入的name(想要加载的文件的相对地址)进行解析,并再次赋值给name

继续分析resolveName方法

resolveName 方法(JDK17)

private String resolveName(String name) {if (!name.startsWith("/")) {String baseName = getPackageName();if (!baseName.isEmpty()) {int len = baseName.length() + 1 + name.length();StringBuilder sb = new StringBuilder(len);name = sb.append(baseName.replace('.', '/'))   // <---- package 中的 . 替换为 /.append('/').append(name)   // <----- package/name.toString();}} else {name = name.substring(1);   // 以 "/" 开头,去掉 "/"}return name;    // 最后的返回结果都是去掉"/"的
}

验证了之前的结论,不加 / ,会 append getPackageName,即:以当前类所在的 package 为基准

classpath: 指的是编译后的class文件、xml、properties等配置文件所在的目录,如下图

因此,""相对地址"/"绝对地址

getResource 之后的代码

接下来再来看看后面的代码

public java.net.URL getResource(String name) {name = resolveName(name);ClassLoader cl = getClassLoader0();   // 获取加载该 Class 的 ClassLoaderif (cl==null) {     // 如果加载该 Class 的 ClassLoader 为 null,则表示这是一个系统 class// A system class.        系统类加载器return ClassLoader.getSystemResource(name); // 调用 ClassLoader 的 getSystemResource 方法}return cl.getResource(name);  // 调用 ClassLoader 的 getResource 方法
}

getResource最终调用的是ClassLoadergetSystemResource方法或者getResource方法
现在来分析ClassLoader类里的getResource方法

 public URL getResource(String name) {URL url;if (parent != null) {url = parent.getResource(name);  //递归调用} else {url = getBootstrapResource(name);   //启动类加载器}if (url == null) {url = findResource(name);   // <----- return null}return url;}

这里涉及到一个知识点 :双亲委派机制
就是如果一个类加载器(用来加载 class 文件)收到了类加载的请求,首先不会自己尝试去加载这个类,而是将请求委派给父类加载器去完成
只有当父类加载器无返完成这个加载请求,子加载起才会尝试自己去完成加载
Java中的类加载器主要分为以下四类:

(1)根类加载器(BootStrapClassLoader), 主要负责加载jre/lib/rt.jar相关的字节码文件的。

(2)扩展类加载器(ExtensionClassLoader), 主要负载加载 jre/lib/ext/*.jar 这些jar包的。 该类加载器在JDK1。9的时候更名为: Platform Class Loader, 其父类加载器为: null。

(3)应用程序类加载器(ApplicationClassLoader), 主要负责加载用户自定义的类以及classpath环境变量所配置的jar包的。 该类加载器在JDK1.9的时候更名为: System ClassLoader, 其父类加载器为: ExtensionClassLoader。

(4)自定义类加载器(UserClassLoader), 负责加载程序员指定的特殊目录下的字节码文件的。大多数情况下,自定义类加载器只需要继承ClassLoader这个抽象类,重写findClass()和loadClass()两个方法即可。

Class.getResourceClassLoader.getResource的区别

Class.getResource:对传入的 name 进行了处理(多了resolveName方法

  • Class.getResource最后返回的name都是去掉/
  • / 会添加 package

ClassLoader.getResource方法,只能处理无 / 的路径,如果一开始加了 /,返回结果为 null

System.out.println(Resource.class.getResource(""));
System.out.println(Resource.class.getResource("/"));System.out.println(ClassLoader.getSystemResource(""));
System.out.println(ClassLoader.getSystemResource("/"));
file:/E:/zy-source-learn/spring-family/springboot3-source-learn/target/classes/cn/zhang/springboot3sourcelearn/demo/
file:/E:/zy-source-learn/spring-family/springboot3-source-learn/target/classes/
file:/E:/zy-source-learn/spring-family/springboot3-source-learn/target/classes/
null

参考
彻底搞懂Class.getResource和ClassLoader.getResource的区别和底层原理
java有几种类加载器?工作原理是什么?

Java 中的 getResource 方法相关推荐

  1. JAVA中复制数组的方法

     在JAVA里面,可以用复制语句"A=B"给基本类型的数据传递值,但是如果A,B是两个同类型的数组,复制就相当于将一个数组变量的引用传递给另一个数组;如果一个数组发生改变,那么 ...

  2. Java中的main()方法详解

    源文作者:leizhimin    源文链接:http://lavasoft.blog.51cto.com/62575/53263 源文作者版权申明: 版权声明:原创作品,允许转载,转载时请务必以超链 ...

  3. 如何在java中调用js方法

    [java] view plain copy/* * 加载脚本引擎,并在java中调用js方法 */ public void test2() { ScriptEngineManager manager ...

  4. java中构造方法和方法全面解析

    java中构造方法和方法全面解析 我相信大多说人都对构造方法.方法不陌生,而且很了解,但我也相信有很多像我这样的没有一个很好很清晰很全面的认识,今天就把它整理如下,希望能给大家带来点方便与帮助,也希望 ...

  5. java中的dispose()方法

    java中的dispose()方法 先来看看 JAVA 1.5 的帮助文档的原文 - dispose - public void dispose() ****** 释放由此 Window.其子组件及其 ...

  6. java 重写方法 访问权限_为何Java中子类重写方法的访问权限不能低于父类中权限(内含里氏替换原则)...

    为何Java中子类重写方法的访问权限不能低于父类中权限 因为 向上转型及Java程序设计维护的原因 例: 假设一个父类A 拥有的方法public void setXXX(){}可以被其他任意对象调用这 ...

  7. Java中重写equals()方法时注意点

    Java中重写equals()方法时注意点 一直说,重写一个对象的equals()方法时我们必须重写HashCode()方法,但是如果我们不重写呢?会有什么影响呢? 首先看一下,什么情况下我们需要重写 ...

  8. JAVA中list.contains()方法,要重写equals(),hashcode()方法

    今天动力节点java培训机构小编为大家介绍"JAVA中list.contains()方法,要重写equals(),hashcode()方法",希望能够帮助正在学习java的零基础学 ...

  9. Java 中的某些方法为什么要求传入一个 Class 对象

    Java 中的某些方法为什么要求传入一个 Class 对象   在 Java 中,某些方法要求传入一个 Class 对象,这能保证该方法能返回一个正确的类型的对象,从而免除返回后的强制类型转换.比如 ...

最新文章

  1. 赵胜男:数据思维,让我的科研和志愿服务动力十足 | 提升之路系列(十二)...
  2. 《好未来编程题》字符串中找出连续最长的数字串
  3. C#实现简单的 Ping 的功能,用于测试网络是否已经联通
  4. 信息学奥赛一本通 1062:最高的分数 | OpenJudge NOI 1.5 05
  5. OpenGL:画个水壶
  6. 【回顾】推荐系统的十二大评价指标总结
  7. Python中的datetime日期格式化
  8. python数值转换机_用于ETL的Python数据转换工具详解
  9. PHP什么函数获取日期,php getdate()函数获取日期信息实例详解
  10. getElementById和ByTagName的区别
  11. 查询和追踪快递单的流向有这么难吗?用VFP其实太简单
  12. unity3d高版本转化低版本
  13. android通讯录管理软件,号簿管理更轻松 Android通讯录软件合集
  14. Film Stocks for Mac(PS胶片模拟调色插件)
  15. Linux线程属性总结
  16. [Python]等额本息房贷计算器
  17. 乘云创数,华为云企业快成长大数据技术创新论坛(深圳站)圆满落幕!
  18. Mac必备软件推荐:Photoshop 2022(ps2022)中文
  19. ListView与ListView适配器
  20. 弹钢琴flash游戏

热门文章

  1. 【JAVA 学习笔记】HashMap 探究
  2. 开发日志:浏览器宽度大于400px,td的宽度按百分比自适应,小于400px时,宽度为指定的值
  3. 顺序表的基本操作C++
  4. Unity UGUI 背景图片自适应文字内容大小
  5. vue 移动端头像裁剪_Vue 头像裁剪控件
  6. 2022-11-16 AndroidS 新建产品lunch
  7. ibatis java.util.Map作为parameterClass和resultClass(转)
  8. python基础知识之整除、取余、幂运算
  9. 第35篇 网络(五)获取本机网络信息
  10. virtualBox 虚拟机安装Windows7系统