leader:学的不错,给你涨薪!JVM的类加载机制你是否理解到我这个程度?

  • main 方法所在的类,总会被首先初始化

  • 首次访问这个类的静态变量或静态方法时

  • 子类初始化,如果父类还没初始化,会引发

  • 子类访问父类的静态变量,只会触发父类的初始化

  • Class.forName

  • new 会导致初始化

不会导致类初始化的情况:

  • 访问类的 static final 静态常量(基本类型和字符串)不会触发初始化

  • 类对象.class 不会触发初始化

  • 创建该类的数组不会触发初始化

  • 类加载器的 loadClass 方法

测试代码:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

验证(测试时请先全部注释,每次只执行其中一个)

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

1.4 练习

======

从字节码分析,使用 a,b,c 这三个常量是否会导致 E 初始化:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

典型应用 - 完成懒惰初始化单例模式:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

以上的实现特点是:

  • 懒惰实例化

  • 初始化时的线程安全是有保障的

2. 类加载器

========

以 JDK 8 为例:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

类加载器的优先级(由高到低):启动类加载器 -> 扩展类加载器 -> 应用程序类加载器 -> 自定义类加载器

2.1 启动类加载器

==========

用 Bootstrap 类加载器加载类:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

执行:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

输出:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

-Xbootclasspath 表示设置 bootclasspath

其中 /a:. 表示将当前目录追加至 bootclasspath 之后

可以有以下几个方式替换启动类路径下的核心类:

  • java -Xbootclasspath: < new bootclasspath>

  • 前追加:java -Xbootclasspath/a:<追加路径>

  • 后追加:java -Xbootclasspath/p:<追加路径>

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

2.2 扩展类加载器

==========

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

程序执行:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

输出结果:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

写一个同名的类:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

打个 jar 包:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

将 jar 包拷贝到JAVA_HOME/jre/lib/ext(扩展类加载器加载的类必须是以jar包方式存在),重新执行 Load5_2

输出:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

2.3 双亲委派模式

==========

所谓的双亲委派,就是指调用类加载器的 loadClass 方法时,查找类的规则。

注意:这里的双亲,翻译为上级似乎更为合适,因为它们并没有继承关系

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

例如:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

执行流程为:

  • sun.misc.Launcher$AppClassLoader // 1 处, 开始查看已加载的类,结果没有

  • sun.misc.Launcher A p p C l a s s L o a d e r / / 2 处,委派上级 s u n . m i s c . L a u n c h e r AppClassLoader // 2 处,委派上级 sun.misc.Launcher AppClassLoader//2处,委派上级sun.misc.LauncherExtClassLoader.loadClass()

  • sun.misc.Launcher$ExtClassLoader // 1 处,查看已加载的类,结果没有

  • sun.misc.Launcher$ExtClassLoader // 3 处,没有上级了,则委派 BootstrapClassLoader 查找

  • BootstrapClassLoader 是在 JAVA_HOME/jre/lib 下找 H 这个类,显然没有

  • sun.misc.Launcher E x t C l a s s L o a d e r / / 4 处,调用自己的 f i n d C l a s s 方法,是在 J A V A _ H O M E / j r e / l i b / e x t 下找 H 这个类,显然没有,回到 s u n . m i s c . L a u n c h e r ExtClassLoader // 4 处,调用自己的 findClass 方法,是在JAVA\_HOME/jre/lib/ext 下找 H 这个类,显然没有,回到 sun.misc.Launcher ExtClassLoader//4处,调用自己的findClass方法,是在JAVA_HOME/jre/lib/ext下找H这个类,显然没有,回到sun.misc.LauncherAppClassLoader 的 // 2 处

  • 继续执行到 sun.misc.Launcher$AppClassLoader // 4 处,调用它自己的 findClass 方法,在 classpath 下查找,找到了

2.4 线程上下文类加载器

=============

我们在使用 JDBC 时,都需要加载 Driver 驱动,不知道你注意到没有,不写

Class.forName(“com.mysql.jdbc.Driver”)

也是可以让 com.mysql.jdbc.Driver 正确加载的,你知道是怎么做的吗? 让我们追踪一下源码:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

先不看别的,看看 DriverManager 的类加载器:

System.out.println(DriverManager.class.getClassLoader());

打印 null,表示它的类加载器是 Bootstrap ClassLoader,回到 JAVA_HOME/jre/lib 下搜索类,但 JAVA_HOME/jre/lib 下显然没有

mysql-connector-java-5.1.47.jar 包,这样问题来了,在 DriverManager 的静态代码块中,怎么能正确加载 com.mysql.jdbc.Driver 呢?

继续看 loadInitialDrivers() 方法:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

先看 2)发现它最后是使用 Class.forName 完成类的加载和初始化,关联的是应用程序类加载器,因此 可以顺利完成类加载

再看 1)它就是大名鼎鼎的 Service Provider Interface (SPI)

约定如下,在 jar 包的 META-INF/services 包下,以接口全限定命名为文件,文件内容是实现类名称

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

这样就可以使用:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

来得到实现类,体现的是【面向接口编程+解耦】的思想,在下面一些框架中都运用了此思想:

  • JDBC

  • Servlet 初始化器

  • Spring 容器

  • Dubbo(对 SPI 进行了扩展)

接着看 ServiceLoader.load 方法:

大厂码农涨薪10k的秘诀:JVM的类加载机制你是否理解到这个程度?

线程上下文类加载器是当前线程使用的类加载器,默认就是应用程序类加载器,它内部又是由 Class.forName 调用了线程上下文类加载器完成类加载,具体代码在 ServiceLoader 的内部类 LazyIterator 中:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

大型分布式系统犹如一个生命,系统中各个服务犹如骨骼,其中的数据犹如血液,而Kafka犹如经络,串联整个系统。这份Kafka源码笔记通过大量的设计图展示、代码分析、示例分享,把Kafka的实现脉络展示在读者面前,帮助读者更好地研读Kafka代码。

麻烦帮忙转发一下这篇文章+关注我

就这一次!拼多多内部架构师培训Kafka源码笔记(现已绝版)

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
671a72faed303032d36.jpg" alt=“img” style=“zoom: 33%;” />

总结

大型分布式系统犹如一个生命,系统中各个服务犹如骨骼,其中的数据犹如血液,而Kafka犹如经络,串联整个系统。这份Kafka源码笔记通过大量的设计图展示、代码分析、示例分享,把Kafka的实现脉络展示在读者面前,帮助读者更好地研读Kafka代码。

麻烦帮忙转发一下这篇文章+关注我

[外链图片转存中…(img-H5A52Hs8-1713214829854)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 29
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值