类加载器详细解释

最近学了反射机制,解除了有关类加载器的一些概念,有些模糊,所以去外网找了一些资料。

本文转载外网文章。

1、类加载器简介

类加载器负责在运行时将 Java 类动态加载到 JVM (Java 虚拟机)。它们也是 JRE(Java 运行时环境)的一部分。因此,借助类加载器,JVM 无需了解底层文件或文件系统即可运行 Java 程序。

此外,这些 Java 类不会一次全部加载到内存中,而是在应用程序需要它们时才会进行加载。这就是类加载器发挥作用的地方,他们负责将类加载到内存中。

在本教程中,我们将讨论不同类型的内置类加载器及其工作方式。然后我们将写一写例子去理解类加载器。

2. 内置类加载器的类型

我们如何用不同的类加载器加载不同的类:

public void printClassLoaders() throws ClassNotFoundException {

    System.out.println("Classloader of this class:"
        + PrintClassLoader.class.getClassLoader());

    System.out.println("Classloader of Logging:"
        + Logging.class.getClassLoader());

    System.out.println("Classloader of ArrayList:"
        + ArrayList.class.getClassLoader());
}

//上面程序的运行结果
// Class loader of this class:sun.misc.Launcher$AppClassLoader@18b4aac2
// Class loader of Logging:sun.misc.Launcher$ExtClassLoader@3caeaf62
// Class loader of ArrayList:null

从上面程序的运行结果可以看出,这里有三种不同的类加载器:应用类加载器(application class loader)、扩展类加载器(extension class loader)和启动类加载器(bootstrap class loader,就是上面运行结果显示为​​ null的)。

应用类加载器加载在classpath中的我们自己写的文件。

扩展类加载器加载核心 Java 类的扩展类(ext/*.jar包下的类)。

启动类加载器是所有其他类加载器的parent(rt.jar包下的类)。

但是,我们可以看到,对于ArrayList,它在输出中显示为null 。这是因为启动加载器是用本机代码(native code)而不是 Java 编写的,因此它不会显示为 Java 类。因此,引导类加载器的行为在不同的 JVM 中会有所不同。

现在让我们更详细地讨论这些类加载器。

2.1。启动类加载器

Java 类由java.lang.ClassLoader的对象/实例加载。但是类加载器本身就是一个类。所以现在的问题是,谁加载java.lang.ClassLoader这个类呢

答案是:启动类加载器。

它主要负责加载 JDK 内部类,通常是rt.jar和其他位于$JAVA_HOME/jre/lib目录下的核心类库。此外,启动类加载器是所有其他ClassLoader实例的parent。

这个启动类加载器是核心 JVM 的一部分,并且是用本机代码(native codde)编写的。根据上面的代码我们可以看到,不同的平台可能有这个特定类加载器的不同实现。

2.2. 扩展类加载器

扩展类加载器是启动类加载器的子类,负责加载核心 Java 类的扩展,以便平台上运行的所有应用程序都可以使用它们。

扩展类加载器从 JDK 扩展目录加载,通常是$JAVA_HOME/lib/ext目录,或java.ext.dirs系统属性中存在的任何其他目录。

2.3.应用/系统类加载器(application class loader)

应用类加载器负责将所有应用程序级别的类加载到 JVM 中。它会加载在类路径环境变量(-classpath-cp命令行选项)中找到的文件。它也是扩展类加载器的子类。

3. 类加载器是如何工作的?

类加载器是 Java 运行时环境的一部分。当 JVM 请求访问一个类时,类加载器会尝试定位该类并使用类的全名将类加载到运行时环境。

java.lang.ClassLoader.loadClass()方法负责将类定义加载到运行时环境。它尝试根据类的全名称加载类。

如果该类还没有被加载过,它会将请求委托给父类加载器。这个过程是递归发生的。

最终,如果父类加载器没有找到该类,那么子类加载器将调用java.net.URLClassLoader.findClass()方法在文件系统本身中查找类。 

如果最后一个子类加载器也无法加载该类,它会抛出java.lang.NoClassDefFoundError或java.lang.ClassNotFoundException。

让我们看一个抛出ClassNotFoundException时的输出示例:

java.lang.ClassNotFoundException: com.baeldung.classloader.SampleClassLoader    
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)    
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)    
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)    
    at java.lang.Class.forName0(Native Method)    
    at java.lang.Class.forName(Class.java:348)

如果我们从调用java.lang.Class.forName()开始往后看,我们可以看到它首先尝试通过父类加载器加载类,然后再通过java.net.URLClassLoader.findClass()寻找这个类。

当它仍然找不到类时,它会抛出ClassNotFoundException。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值