iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >什么是类加载器
  • 906
分享到

什么是类加载器

2023-06-15 14:06:14 906人浏览 泡泡鱼
摘要

本篇内容主要讲解“什么是类加载器”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“什么是类加载器”吧!类加载器简介Java程序被编译器编译之后成为字节码文件(.class文件),当程序需要某个类时,

本篇内容主要讲解“什么是类加载器”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“什么是类加载器”吧!

什么是类加载器

类加载器简介

Java程序被编译器编译之后成为字节码文件(.class文件),当程序需要某个类时,虚拟机便会将对应的class文件进行加载,创建出对应的Class对象。而这个将class文件加载到虚拟机内存的过程,便是类加载。

什么是类加载器

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

Java类不会一次全部加载到内存中,而是在应用程序需要时才会加载。此时,类加载器负责将类加载到内存中。

类加载的过程

类的生命周期通常包括:加载、链接、初始化、使用和卸载。上图中包含了类加载的三个阶段:加载阶段、链接阶段和初始化阶段。如果将这三个阶段再拆分细化包括:加载、验证、准备、解析和初始化。

什么是类加载器

关于这几个阶段的作用,已经有很多文章在写了,我们就简单概况一下:

  • 加载:通过一个类的完全限定查找类字节码文件,转化为方法区运行时的数据结构,创建一个代表该类的Class对象。

  • 验证:确保Class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全

  • 准备:为类变量(即static修饰的字段变量)分配内存并且设置该类变量的初始值。不包含被final修饰的static变量,因为它在编译时已经分配了。

  • 解析:将常量池内的符号引用转换为直接引用的过程。如果符号引用指向一个未被加载的类,或者未被加载类的字段或方法,那么解析将触发这个类的加载。

  • 初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量。

在上述类加载的过程中,虚拟机内部提供了三种类加载器:启动(Bootstrap)类加载器、扩展(Extension)类加载器、系统(System)类加载器(也称应用类加载器)。

下面就讨论不同类型的内置类加载器是如何工作,以及介绍如何自定义类加载器。

内置类加载器

先从一个简单的例子来看一下如何使用不同的加载器来加载不同的类:

public void printClassLoaders() {      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()); }

执行上述程序,打印如下内容:

Classloader of this class:sun.misc.Launcher$AppClassLoader@18b4aac2 Classloader of Logging:sun.misc.Launcher$ExtClassLoader@2f0e140b Classloader of ArrayList:null

上述三行输出分别对应三种不同的类加载器:系统(System)类加载器、扩展(Extension)类加载器和启动(Bootstrap)类加载器(显示为null)。

系统程序类加载器加载包含示例方法的类,也就是将我们自己的文件加载到类路径中。扩展类加载器加载Logging类,也就是加载作为标准核心Java类扩展的类。启动类加载器加载ArrayList类,是所有其他类的父级。

对于ArrayList的类加载器,输出为null。这是因为启动类加载器是用本机代码实现而不是Java,因此它不会显示为Java类。启动类加载器在操作在不同的JVM中会有所不同。

上述三种类加载器,外加自定义类加载器,它们直接的关系可用下图表示:

什么是类加载器

现在来具体看一下这些类加载器。

Bootstrap类加载器

Java类由java.lang.ClassLoader的实例加载。但是,类加载器本身就是类。那么,谁来加载java.lang.ClassLoader?对,就是启动类加载器。

启动类加载器主要负责加载jdk内部类,通常是rt.jar和$JAVA_HOME/jre/lib目录中的其他核心库。此外,Bootstrap类加载器还充当所有其他ClassLoader实例的父类。

该启动程序类加载器是Java虚拟机的一部分,用本机代码编写(比如,c++),不同的平台的实现可能有所不同。

出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类。

Extension类加载器

扩展类加载器是启动类加载器的子类,Java语言编写,由sun.misc.Launcher$ExtClassLoader实现,父类加载器为启动类加载器,负责加载标准核心Java类的扩展。

扩展类加载器从JDK扩展目录(通常是$JAVA_HOME/lib/ext目录)或java.ext.dirs系统属性中指定的任何其他目录进行自动加载。

系统类加载器

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

系统类加载器,也称应用程序加载器是指  Sun公司实现的sun.misc.Launcher$AppClassLoader,负责加载系统类路径-classpath或-D  java.class.path指定路径下的类库,也就是我们经常用到的classpath路径,开发者可以直接使用系统类加载器,一般情况下该类加载是程序中默认的类加载器,通过ClassLoader#getSystemClassLoader()方法可以获取到该类加载器。

类加载器是如何工作的

类加载器是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)

上述过程,通常我们称作双亲委派机制。双亲委派机制要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器,请注意双亲委派机制中的父子关系并非通常所说的类继承关系,而是采用组合关系来复用父类加载器的相关代码。

除外,类加载器还具有三个重要功能:委派模型、类的唯一性和可见性。

委派模型

类加载器遵循委派模型,在该模型中,根据请求查找类或资源,ClassLoader实例会将对类或资源的搜索委托给父类加载器。

假设我们有一个将应用程序类加载到JVM中的请求。系统类加载器首先将该类的加载委托给其父扩展类加载器,而父扩展类加载器又将其委托给引导类加载器。

仅当启动类加载器和扩展类加载器都未能成功加载类时,系统类加载器才会尝试加载类本身。

类的唯一性

作为委托模型的结果,很容易确保类的唯一性,因为始终尝试向上委托。如果父类加载器无法找到该类,则只有当前实例自己会尝试进行查找和加载。

可见性

此外,子类加载器对其父类加载器加载的类可见。例如,系统类加载器加载的类对扩展和Bootstrap类加载器加载的类具有可见性,反之亦然。

比如,通过系统类加载器加载类A,而通过扩展类加载器加载类B,则对系统类加载器加载的其他类而言,A和B类都是可见的。但对扩展类加载器加载的其他类而言,类B是唯一可见的类。

自定义类加载器

在大多数情况下,如果文件已经在文件系统中,则内置的类加载器就足够了。但是,在需要从本地硬盘驱动器或网络中加载类的情况下,可能需要使用自定义类加载器。下面介绍自定义类加载器的使用。

自定义类加载器示例

自定义类加载器不仅对在运行时加载类有帮助,还有一些特殊的场景:

  • 帮助修改现有的字节码,例如weaving agents;

  • 动态创建适合用户需求的类。例如在JDBC中,通过动态类加载完成不同驱动程序实现之间的切换。

  • 在为具有相同名称和程序包的类加载不同的字节码时,实现类版本控制机制。这可以通过URL类加载器(通过URL加载jar)或自定义类加载器来完成。

举一个更具体的例子,比如,浏览器使用自定义类加载器从网站加载可执行内容。浏览器可以使用单独的类加载器从不同的网页加载applet。用于运行applet的applet查看器包含一个ClassLoader,该类加载器可访问远程服务器上的网站,而无需查看本地文件系统。

然后通过Http加载原始字节码文件,并将其转换为JVM中的类。即使这些applet具有相同的名称,但如果由不同的类加载器加载,它们也被视为不同的组件。

现在,我们了解了为什么自定义类加载器是相关的,让我们实现ClassLoader的子类来扩展和总结JVM如何加载类的。

创建自定义类加载器

自定义类加载器通常通过继承java.lang.ClassLoader类,重写findClass()方法:

public class CustomClassLoader extends ClassLoader {      @Override     public Class findClass(String name) throws ClassNotFoundException {         byte[] b = loadClassFromFile(name);         return defineClass(name, b, 0, b.length);     }      private byte[] loadClassFromFile(String fileName)  {         InputStream inputStream = getClass().getClassLoader().getResourceAsStream(                 fileName.replace('.', File.separatorChar) + ".class");         byte[] buffer;         ByteArrayOutputStream byteStream = new ByteArrayOutputStream();         int nextValue = 0;         try {             while ( (nextValue = inputStream.read()) != -1 ) {                 byteStream.write(nextValue);             }         } catch (IOException e) {             e.printStackTrace();         }         buffer = byteStream.toByteArray();         return buffer;     } }

在上面的示例中,我们定义了一个自定义类加载器,该类加载器扩展了默认类加载器并从指定文件加载字节数组。如果没有太复杂的需求,可以直接继承URLClassLoader类,重写loadClass方法,具体可参考AppClassLoader和ExtClassLoader。

了解java.lang.ClassLoader

下面来看看java.lang.ClassLoader类中的一些基本方法,以更清楚地了解其工作方式。

loadClass方法

public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {

此方法负责加载给定名称参数的类。name参数为类的全限定名。

Java虚拟机调用loadClass()方法来解析类引用,并将resolve设置为true。但是,不一定总是要解析一个类。如果只需要确定该类是否存在,则将resolve参数设置为false。

此方法用作类加载器的入口。我们可以尝试从java.lang.ClassLoader的源代码中了解loadClass()方法的内部工作:

protected Class<?> loadClass(String name, boolean resolve)   throws ClassNotFoundException {          synchronized (getClassLoadingLock(name)) {         // First, check if the class has already been loaded         Class<?> c = findLoadedClass(name);         if (c == null) {             long t0 = System.nanoTime();                 try {                     if (parent != null) {                         c = parent.loadClass(name, false);                     } else {                         c = findBootstrapClassOrNull(name);                     }                 } catch (ClassNotFoundException e) {                     // ClassNotFoundException thrown if class not found                     // from the non-null parent class loader                 }                  if (c == null) {                     // If still not found, then invoke findClass in order                     // to find the class.                     c = findClass(name);                 }             }             if (resolve) {                 resolveClass(c);             }             return c;         }     }

该方法的默认实现按以下顺序搜索类:

  • 调用findLoadedClass(String)方法以查看是否已加载该类。

  • 在父类加载器上调用loadClass(String)方法。

  • 调用findClass(String)方法以查找类。

defineClass方法

protected final Class defineClass(  String name, byte[] b, int off, int len) throws ClassFORMatError

此方法负责将字节数组转换为类的实例。如果数据不包含有效的类,则会抛出ClassFormatError。另外,由于此方法被标记为final,因此我们无法覆盖此方法。

findClass方法

protected Class<?> findClass(   String name) throws ClassNotFoundException

此方法查找以标准名称作为参数的类。我们需要在遵循委派模型加载类的自定义类加载器实现中重写此方法。

另外,如果父类加载器找不到请求的类,则loadClass()会调用此方法。如果没有任何类加载器的父类找到该类,则默认实现会抛出ClassNotFoundException异常。

getParent方法

public final ClassLoader getParent()

此方法返回父类加载器以进行委派。某些实现使用null来表示启动类加载器。

getResource方法

public URL getResource(String name)

此方法尝试查找具有给定名称的资源。它将首先委托给资源的父类加载器,如果父级为null,则搜索虚拟机内置的类加载器的路径。如果失败,则该方法将调用findResource(String)来查找资源。

指定为输入的资源名称可以相对于类路径,也可以是相对于绝对路径。

它返回用于读取资源的URL对象;如果找不到资源或调用者没有足够的特权来返回资源,则返回null。

需要注意的是,Java是从类路径中加载资源。

最后,Java中的资源加载被认为是与位置无关的,因为只要设置了环境来查找资源,代码在何处运行都无关紧要。

上下文类加载器

通常,上下文类加载器为J2SE中引入的类加载委托方案提供了一种替代方法。JVM中的类加载器遵循分层模型,因此每个类加载器都有一个单独的父类,而启动类加载器除外。但是,有时当JVM核心类需要动态加载应用程序开发人员提供的类或资源时,可能会遇到问题。

例如,在JNDI中,核心功能由rt.jar中的引导程序类实现。但是这些JNDI类可能会加载由独立供应商实现的JNDI提供程序(部署在应用程序类路径中)。这种情况要求启动类加载器(父类加载器)加载对应程序加载器(子类加载器)可见的类。

线程上下文类加载器(context class loader)是从JDK 1.2开始引入的。Java.lang.Thread中的方法  getContextClassLoader()和setContextClassLoader(ClassLoader  cl)用来获取和设置线程的上下文类加载器。如果没有通过setContextClassLoader(ClassLoader  cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。Java应用运行的初始线程的上下文类加载器是系统类加载器,在线程中运行的代码可以通过此类加载器来加载类和资源。

线程上下文类加载器从根本解决了一般应用不能违背双亲委派模式的问题,使得java类加载体系显得更灵活。上面所提到的问题正是线程上下文类加载器的拿手好菜。如果不做任何的设置,Java应用的线程上下文类加载器默认就是系统类加载器。因此,在SPI接口的代码中使用线程上下文类加载器,就可以成功的加载到SPI实现的类。

到此,相信大家对“什么是类加载器”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: 什么是类加载器

本文链接: https://www.lsjlt.com/news/280518.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 什么是类加载器
    本篇内容主要讲解“什么是类加载器”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“什么是类加载器”吧!类加载器简介Java程序被编译器编译之后成为字节码文件(.class文件),当程序需要某个类时,...
    99+
    2023-06-15
  • jvm类加载器,类加载机制是什么
    这篇文章主要介绍“jvm类加载器,类加载机制是什么”,在日常操作中,相信很多人在jvm类加载器,类加载机制是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”jvm类加载器,类加载机制是什么”的疑惑有所帮助!...
    99+
    2023-06-16
  • 什么是JVM的类加载器
    本篇内容主要讲解“什么是JVM的类加载器”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“什么是JVM的类加载器”吧!1. 什么是JVM既然是学习关于JVM的相关理论知识,我们当然得知道什么是JVM...
    99+
    2023-06-16
  • Java类加载器以及类加载器的委托模型是什么
    本篇内容介绍了“Java类加载器以及类加载器的委托模型是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!我们知道,我们在Java中用到的所...
    99+
    2023-06-17
  • Java类加载器的特色是什么
    这篇文章主要介绍“Java类加载器的特色是什么”,在日常操作中,相信很多人在Java类加载器的特色是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java类加载器的特色是什么”的疑惑有所帮助!接下来,请跟...
    99+
    2023-06-15
  • tomcat类加载机制是什么
    Tomcat的类加载机制是指Tomcat服务器在运行过程中,如何加载和管理Java类文件的过程。它主要包括以下几个步骤:1. Boo...
    99+
    2023-09-15
    tomcat
  • spring类加载过程是什么
    Spring框架的类加载过程主要分为以下几步: 扫描配置文件:Spring框架通过配置文件来定义和管理Bean,在启动时会扫描配...
    99+
    2024-02-29
    spring
  • JAVA类的加载过程是什么
    JAVA类的加载过程主要分为加载、链接和初始化三个阶段。 加载:类加载是指将类的.class文件从文件系统或网络加载到内存中,并...
    99+
    2023-10-26
    JAVA
  • Java类的加载机制是什么
    这篇文章主要讲解了“Java类的加载机制是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java类的加载机制是什么”吧!1、什么是类的加载类的加载指的是将类的.class文件中的二进制数...
    99+
    2023-06-17
  • spring类的加载机制是什么
    Spring框架的类加载机制主要涉及到两个方面:类路径扫描和类加载器。 类路径扫描:Spring框架在启动时会扫描应用程序的类路...
    99+
    2024-04-02
  • Tomcat类加载器的工作原理是什么
    Tomcat类加载器的工作原理是通过使用Java类加载器来加载Web应用程序的类。Tomcat使用了一种层次结构的类加载器体系,每个...
    99+
    2024-04-02
  • Java类加载器的组织结构是什么
    本篇内容主要讲解“Java类加载器的组织结构是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java类加载器的组织结构是什么”吧!首先回顾一下,java虚拟机载入java类的步骤:java文...
    99+
    2023-06-17
  • Java中类的加载顺序是什么
    本篇文章为大家展示了Java中类的加载顺序是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。具体如下:public class Parent { public static int a = pa...
    99+
    2023-05-31
    java 中类 ava
  • java类的加载的过程是什么
    Java类的加载过程包括以下步骤: 加载(Loading):将类的字节码文件加载到内存中。这个阶段由类加载器完成,类加载器将字节...
    99+
    2023-10-28
    java
  • Java中的类加载是什么意思
    本篇内容主要讲解“Java中的类加载是什么意思”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java中的类加载是什么意思”吧!目录类加载<1>.父子类执行的顺序<2>类加...
    99+
    2023-06-20
  • Java类的加载时机是什么时候
    本篇内容主要讲解“Java类的加载时机是什么时候”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java类的加载时机是什么时候”吧!必须初始化的四种情况有四种情况类是必须要进行初始化的,对于这四种...
    99+
    2023-06-25
  • Java自定义类加载器及JVM自带的类加载器之间的交互关系是什么
    这篇“Java自定义类加载器及JVM自带的类加载器之间的交互关系是什么”文章,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要参考一下,对于“Java自定义类加载器及JVM自带的类加载器之间的交互关系是什么”,小编整理...
    99+
    2023-06-06
  • Java类的加载时机与过程是什么
    本篇内容主要讲解“Java类的加载时机与过程是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java类的加载时机与过程是什么”吧!1 开门见山以前曾经看到过一个java的面试题,当时觉得此题...
    99+
    2023-06-25
  • 类的加载、链接和初始化是什么
    本篇内容介绍了“类的加载、链接和初始化是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Java 类的加载Java类的加载是由类加载器来完...
    99+
    2023-06-16
  • Java中父子类的加载顺序是什么
    今天就跟大家聊聊有关Java中父子类的加载顺序是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1. 静态 > 非静态当且仅当该类在程序中第一次被 new(是第一次被类加载器...
    99+
    2023-06-20
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作