欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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/
        */
    }
}

双亲委派模型

  1. 所有的类加载器都是有层级结构的,每个类加载器都有一个父类类加载器(通过组合实现,而不是继承),除了启动类加载器(Bootstrap ClassLoader);
  2. 当一个类加载器接收到一个类加载请求时,首先将这个请求委派给它的父加载器去加载,所以每个类加载请求最终都会传递到顶层的启动类加载器,如果父加载器无法加载时,子类加载器才会去尝试自己去加载。

类加载器层级结构

  • 启动类加载器(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 下所指定的类库,如果应用程序没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

class.getResource和classLoader.getResource的区别

相关标签: java jvm