专栏首页JavaEdge看完这篇JVM类加载器,我也能吊打面试官了

看完这篇JVM类加载器,我也能吊打面试官了

0 前言

全是干货的技术殿堂

文章收录在我的 GitHub 仓库,欢迎Star/fork: Java-Interview-Tutorial https://github.com/Wasabi1234/Java-Interview-Tutorial

类加载器是如何定位具体的类文件并读取的呢?

在类加载器家族中存在着类似人类社会的权力等级制度

  • 最高层的Bootstrap 在JVM启动时创建的,通常由与操作系统相关的本地代码实现,是最根基的类加载器,负责装载最核心的Java类,比如Object、System、 String ,Java运行时的rt.jar等jar包
  • JDK9的Platform ClassLoader 负责加载<JAVA_HOME>\lib\ext目录中的,或者java.ext.dirs系统变量指定的路径中的所以类库; 加载一些扩展的系统类,比如XML、加密、压缩相关的功能类等; JDK9之前是Extension ClassLoader.
  • 第三层 Application ClassLoader 应用类加载器,主要是加载用户定义的CLASSPATH路径下的类

第二、三层类加载器为Java语言实现,用户也可以自定义类加载器 查看本地类加载器的方式如下:

在JDK8环境中,执行结果如下

AppClassLoader的Parent为Bootstrap,它是通过C/C++实现的,并不存在于JVM体系内,所以输出为 null

低层次的当前类加载器,不能覆盖更高层次类加载器已经加载的类 如果低层次的类加载器想加载一个未知类,要非常礼貌地向上逐级询问:“请问,这个类已经加载了吗?” 被询问的高层次类加载器会自问两个问题

  • 我是否已加载过此类
  • 如果没有,是否可以加载此类

只有当所有高层次类加载器在两个问题的答案均为“否”时,才可以让当前类加载器加载这个未知类 左侧绿色箭头向上逐级询问是否已加载此类,直至Bootstrap ClassLoader,然后向下逐级尝试是否能够加载此类,如果都加载不了,则通知发起加载请求的当前类加载器,准予加载 在右侧的三个小标签里,列举了此层类加载器主要加载的代表性类库,事实上不止于此

通过如下代码可以查看Bootstrap 所有已加载类库

执行结果

Bootstrap加载的路径可以追加,不建议修改或删除原有加载路径 在JVM中增加如下启动参数,则能通过Class.forName正常读取到指定类,说明此参数可以增加Bootstrap的类加载路径:

-Xbootclasspath/a:/Users/sss/book/ easyCoding/byJdk11/src

如果想在启动时观察加载了哪个jar包中的哪个类,可以增加

-XX:+TraceClassLoading

此参数在解决类冲突时非常实用,毕竟不同的JVM环境对于加载类的顺序并非是一致的 有时想观察特定类的加载上下文,由于加载的类数量众多,调试时很难捕捉到指定类的加载过程,这时可以使用条件断点功能 比如,想查看HashMap的加载过程,在loadClass处打个断点,并且在condition框内输入如图

JVM如何确立每个类在JVM的唯一性

类的全限定名和加载这个类的类加载器的ID

在学习了类加载器的实现机制后,知道双亲委派模型并非强制模型,用户可以自定义类加载器,在什么情况下需要自定义类加载器呢?

  • 隔离加载类 在某些框架内进行中间件与应用的模块隔离,把类加载到不同的环境 比如,阿里内某容器框架通过自定义类加载器确保应用中依赖的jar包不会影响到中间件运行时使用的jar包
  • 修改类加载方式 类的加载模型并非强制,除Bootstrap外,其他的加载并非一定要引入,或者根据实际情况在某个时间点进行按需进行动态加载
  • 扩展加载源 比如从数据库、网络,甚至是电视机机顶盒进行加载
  • 防止源码泄露 Java代码容易被编译和篡改,可以进行编译加密。那么类加载器也需要自定义,还原加密的字节码。

实现自定义类加载器的步骤

  • 继承ClassLoader
  • 重写findClass()方法
  • 调用defineClass()方法

一个简单的类加载器实现的示例代码如下

由于中间件一般都有自己的依赖jar包,在同一个工程内引用多个框架时,往往被迫进行类的仲裁 按某种规则jar包的版本被统一指定, 导致某些类存在包路径、类名相同的情况,就会引起类冲突,导致应用程序出现异常 主流的容器类框架都会自定义类加载器,实现不同中间件之间的类隔离,有效避免了类冲突。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 类加载器与双亲委派模型1 类加载器 2 双亲委派模型

    类加载器(ClassLoader)是Java语言的一项创新,也是Java流行的一个重要原因。 在类加载的第一阶段“加载”过程中,需要通过一个类的全限定名来获取...

    JavaEdge
  • JVM实战---类加载的过程

    在加载类时,使用的是Parents Delegation Model(溯源委派加载模型)

    JavaEdge
  • JVM实战 - 类加载的过程

    任何程序都需要加载到内存才能与CPU进行交流 同理, 字节码.class文件同样需要加载到内存中,才可以实例化类 ClassLoader的使命就是提前加载....

    JavaEdge
  • jvm启动加载类的全过程,全网最全一篇,告诉你什么是双亲委派机制

    今天我们来讲讲jvm里类加载的过程,我们写了那么多类,却不知道类的加载过程,岂不是很尴尬。

    公众号 IT老哥
  • 类加载

    启动类加载器,Bootstrap ClassLoader,加载JACA_HOME\lib,或者被-Xbootclasspath参数限定的类 扩展类加载器,Ex...

    葆宁
  • JVM如何加载.class文件

    JVM 中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java 中的类加载器是一个重要的Java 运行时系统组件,它负责在运行时查找和...

    葆宁
  • 深入探究JVM之类加载与双亲委派机制

    前面学习了虚拟机的内存结构、对象的分配和创建,但对象所对应的类是怎么加载到虚拟机中来的呢?加载过程中需要做些什么?什么是双亲委派机制以及为什么要打破双亲委派机制...

    夜勿语
  • Java类加载机制详解

    Java类加载器负责加载所有的类,系统会为所有被载入内存的类生成一个java.lang.Class实例。对于同一个类,一旦被加载如内存中,就不会被再次加载。JV...

    张申傲
  • 谈谈类加载器的双亲委派机制

    负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类

    葆宁
  • 深入理解类加载机制:拨开迷雾见真章

    我们平常写的Java代码是存储在.java文件中,这是一个文本文件,是不能直接执行的,但是这个文本文件可以被编译成为一个字节码文件(后缀为.class),这个字...

    itlemon

扫码关注云+社区

领取腾讯云代金券