class.getResource和classLoader.getResource的区别
程序员文章站
2022-05-27 15:16:25
...
先说结论:
Class.getResource和ClassLoader.getResource的区别:
- 在加载资源文件的时候,加载方式的不同,Class.getResource和ClassLoader.getResource本质上是一样的,都是使用ClassLoader.getResource加载资源的,class.getResource("/") == class.getClassLoader().getResource("")
- Class.getResource真正调用ClassLoader.getResource方法之前,会先获取文件的路径(path不以’/‘开头时,默认是从此类所在的包下取资源;path以’/'开头时,则是从项目的ClassPath根下获取资源)。
- ClassLoader.getResource方法会通过双亲委派机制,先委派双亲去加载类,如果双亲没有加载到,则再由自己加载。
示例如下:
public class App
{
public static void main( String[] args ) throws IOException
{
/**
* 类名.class.getResource 获取该“类名.class”文件所在的包下的绝对路径,即“项目绝对路径/target/classes/包名/”
* 类名.class.getResource("/") 获取的是编译后的“项目根目录”绝对路径,即“项目绝对路径/target/classes/”
* classLoader获取的是项目加载器
*/
System.out.println( "App.class.getResource() :" + App.class.getResource(""));
System.out.println( "App.class.getResource('/') :" + App.class.getResource("/"));
System.out.println( "App.class.getClassLoader().getResource() :" + App.class.getClassLoader().getResource(""));
System.out.println( "App.class.getClassLoader().getResource('/'):" + App.class.getClassLoader().getResource("/"));
System.out.println( "XXX.class.getResource('/') :" + KafkaConsumerTest.class.getResource(""));
System.out.println( "XXX.class.getClassLoader().getResource('/'):" + KafkaConsumerTest.class.getClassLoader().getResource(""));
/*
输出:
App.class.getResource() :file:/C:/Users/Administrator/IdeaProjects/KafkaTestArifactId/target/classes/com/lumin/KafkaTestGroup/
App.class.getResource('/') :file:/C:/Users/Administrator/IdeaProjects/KafkaTestArifactId/target/classes/
App.class.getClassLoader().getResource() :file:/C:/Users/Administrator/IdeaProjects/KafkaTestArifactId/target/classes/
App.class.getClassLoader().getResource('/'):null
XXX.class.getResource('/') :file:/C:/Users/Administrator/IdeaProjects/KafkaTestArifactId/target/classes/com/lumin/KafkaTestConsumerGroup/
XXX.class.getClassLoader().getResource('/'):file:/C:/Users/Administrator/IdeaProjects/KafkaTestArifactId/target/classes/
*/
}
}
双亲委派模型
- 所有的类加载器都是有层级结构的,每个类加载器都有一个父类类加载器(通过组合实现,而不是继承),除了启动类加载器(Bootstrap ClassLoader);
- 当一个类加载器接收到一个类加载请求时,首先将这个请求委派给它的父加载器去加载,所以每个类加载请求最终都会传递到顶层的启动类加载器,如果父加载器无法加载时,子类加载器才会去尝试自己去加载。
类加载器层级结构
- 启动类加载器(Bootstrap/Primordial/NULL ClassLoader):顶层的类加载器,没有父类加载器。负责加载 /lib 目录下的,或则被 -Xbootclasspath 参数所指定路径中的,并被 JVM 识别的(仅按文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录也不会被加载)类库加载到虚拟机内存中。所有被 Bootstrap classloader 加载的类,它的 Class.getClassLoader 方法返回的都是 null,所以也称作 NULL ClassLoader。
- 扩展类加载器(Extension CLassLoader):由 sun.misc.Launcher$ExtClassLoader 实现,负责加载 <JAVA_HOME>/lib/ext 目录下,或被 java.ext.dirs 系统变量所指定的目录下的所有类库;
- 应用程序类加载器(Application/System ClassLoader):由 sun.misc.Launcher$AppClassLoader 实现。它是 ClassLoader.getSystemClassLoader() 方法的默认返回值,所以也称为系统类加载器(System ClassLoader)。它负责加载 classpath 下所指定的类库,如果应用程序没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
上一篇: 高血压的最佳养生水果,改善血液循环
下一篇: 这6个动作每天练10分钟,帮助缓解肩周炎