1. 什么是类加载器?

类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 类的虚拟机使用 Java 方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。

2. JVM类加载机制

  • 全盘负责,当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
  • 父类委托,先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
  • 缓存机制,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效

3. 类加载器与类的”相同“判断

类加载器除了用于加载类外,还可用于确定类在Java虚拟机中的唯一性。

即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。

通俗一点来讲,要判断两个类是否“相同”,前提是这两个类必须被同一个类加载器加载,否则这个两个类不“相同”。 这里指的“相同”,包括类的Class对象的equals()方法、isAssignableFrom()方法、isInstance()方法、instanceof关键字等判断出来的结果。

类加载器种类

  • 启动类加载器,Bootstrap ClassLoader,加载JACA_HOMElib,或者被-Xbootclasspath参数限定的类,该类加载器加载的是核心类库,是由C语言实现的,所以在java代码中获取该类加载器比如String会获取到null,因为它不是java类。
  • 扩展类加载器,Extension ClassLoader,加载libext,或者被java.ext.dirs系统变量指定的类
  • 应用程序类加载器,Application ClassLoader,加载ClassPath中的类库或者我们自己写的代码。
  • 自定义类加载器,通过继承ClassLoader实现,一般是加载我们的自定义类

按照这个过程可以想到,如果同样在CLASSPATH指定的目录中和自己工作目录中存放相同的class,会优先加载CLASSPATH目录中的文件。

双亲委派模型

总结: 自底向上检查类是否加载,自顶向下加载类。

目的:避免同一个类被多次加载,避免有重复的字节码出现,保证Java程序安全稳定运行。

双亲指的是什么:parents中文翻译的结果。其实指的是所有父类。

类加载过程

加载(ClassLoader的loadClass()方法)

  1. 根据类的全限定名读取字节码到jvm内部。
  2. 将Class文件转换为运行时数据结构(存储到方法区中)
  3. 转换为一个与目标类型对应的java.lang.Class对象

类加载方式

  1. 命令行启动应用时候由JVM初始化加载
  2. 通过Class.forName()方法动态加载,默认会执行初始化块,执行类中的static块(jdbc driver)
  3. 通过ClassLoader.loadClass()方法动态加载,不会执行初始化块

连接

  1. 验证(文件格式验证、元数据验证、字节码验证和符号引用验证)
  2. 准备(为类中的所有静态变量分配内存空间,并为其设置一个初始默认值(由于还没有产生对象,实例变量将不再此操作范围内))
  3. 解析(将常量池中所有的符号引用转为直接引用(得到类或者字段、方法在内存中的指针或者偏移量,以便直接调用该方法)。这个阶段可以在初始化之后再执行)

再补充一个常识,Class.loadClass()执行完获得的对象是连接后的对象。

初始化

在连接的准备阶段,类变量已赋过一次系统要求的初始值,而在初始化阶段,则是根据程序员自己写的逻辑去初始化类变量和其他资源。比如int a=6;

注意这个初始化和连接-准备阶段的初始化不同,连接-准备中初始化赋的值是基础类型的默认值,而这里是真正我们赋值的值。

类的声明周期

  1. 加载
  2. 连接
  3. 初始化
  4. 使用
  5. 卸载

Java虚拟机如何结束生命周期

  1. 执行System.exit()方法
  2. 程序正常执行结束
  3. 程序执行遇到异常或Error终止
  4. 操作系统出错而导致java虚拟机运行终止

何时触发初始化

  1. 为一个类型创建一个新的对象实例时(比如new、反射、序列化)
  2. 调用一个类型的静态方法时(即在字节码中执行invokestatic指令)
  3. 调用一个类型或接口的静态字段,或者对这些静态字段执行赋值操作时(即在字节码中,执行getstatic或者putstatic指令),不过用final修饰的静态字段除外,它被初始化为一个编译时常量表达式
  4. 调用JavaAPI中的反射方法时(比如调用java.lang.Class中的方法,或者java.lang.reflect包中其他类的方法)
  5. 初始化一个类的派生类(子类)时(Java虚拟机规范明确要求初始化一个类时,它的超类必须提前完成初始化操作,接口例外)
  6. JVM启动包含main方法的启动类时。

注意:通过子类引用付了的静态字段,不会导致子类初始化。

自定义类加载器

要创建用户自己的类加载器,只需要继承java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,即指明如何获取类的字节码流。

如果要符合双亲委派规范,则重写findClass方法(用户自定义类加载逻辑);要破坏的话,重写loadClass方法(双亲委派的具体逻辑实现)。

JAVA热部署实现

首先谈一下何为热部署(hotswap),热部署是在不重启 Java 虚拟机的前提下,能自动侦测到 class 文件的变化,更新运行时 class 的行为。Java 类是通过 Java 虚拟机加载的,某个类的 class 文件在被 classloader 加载后,会生成对应的 Class 对象,之后就可以创建该类的实例。默认的虚拟机行为只会在启动时加载类,如果后期有一个类需要更新的话,单纯替换编译的 class 文件,Java 虚拟机是不会更新正在运行的 class。如果要实现热部署,最根本的方式是修改虚拟机的源代码,改变 classloader 的加载行为,使虚拟机能监听 class 文件的更新,重新加载 class 文件,这样的行为破坏性很大,为后续的 JVM 升级埋下了一个大坑。

另一种友好的方法是创建自己的 classloader 来加载需要监听的 class,这样就能控制类加载的时机,从而实现热部署。

热部署步骤

  1. 销毁自定义classloader(被该加载器加载的class也会自动卸载);
  2. 更新class
  3. 使用新的ClassLoader去加载class

JVM中的Class只有满足以下三个条件,才能被GC回收,也就是该Class被卸载(unload):

  • 该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。
  • 加载该类的ClassLoader已经被GC。
  • 该类的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法

可见性机制及单一性机制

可见性机制:子类加载器可以看到父类加载器加载的类,而反之则不行.

单一性机制:父加载器加载过的类不能被子加载器加载第二次。虽然重写违反委托和单一性机制的类加载器是可能的,但这样做并不可取。

深入loadClass 源码

public Class<?> loadClass(String name)throws ClassNotFoundException {return loadClass(name, false);}protected synchronized Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException {// 首先判断该类型是否已经被加载Class c = findLoadedClass(name);if (c == null) {//如果没有被加载,就委托给父类加载或者委派给启动类加载器加载try {if (parent != null) {//如果存在父类加载器,就委派给父类加载器加载c = parent.loadClass(name, false);} else {//如果不存在父类加载器,就检查是否是由启动类加载器加载的类,通过调用本地方法native Class findBootstrapClass(String name)c = findBootstrapClass0(name);}} catch (ClassNotFoundException e) {// 如果父类加载器和启动类加载器都不能完成加载任务,才调用自身的加载功能c = findClass(name);}}if (resolve) {resolveClass(c);}return c;}
}

可以看到,这个方法维护了一个双亲委派模型,所以我们在自定义ClassLoader时,尽量不要重写loadClass方法,除非你要破坏这个模型。

关注公众号【程序论】,领取海量的学习资源,还有免费的面试指南等你来哦

c调用其他类的方法_吊打面试官-类加载器相关推荐

  1. 重复订单号校验_吊打面试官系列重复消费、顺序消费、分布式事务

    你知道的越多,你不知道的越多 前言 消息队列在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在消息队列的使用和原理方面对小伙伴们进行360°的刁难. 作为一个在互联网公司面一次拿一次Of ...

  2. 如何查找历史线程阻塞原因_吊打面试官!Java多线程并发 108 道题,你能答对多少?...

    多线程并发108题 1.Java中实现多线程有几种方法 2.继承Thread 类 3.实现Runnable 接口. 4.ExecutorService. Callable. Future 有返回值线程 ...

  3. qt定时器是阻塞的吗_吊打面试官 | 面试官:TCP真的可靠吗

    点击蓝字关注我哦 以下是本期干货视频视频后还附有文字版本哦 ▼<面试官:TCP真的可靠吗>▼ ps:请在WiFi环境下打开,如果有钱任性请随意 TCP真的可靠吗 面试官经常会问的一个问题是 ...

  4. mabatisplus怎么给实体类自定义属性_吊打面试官之:当实体类中的属性名和表中的字段名不一样 ,怎么办 ?...

    第1种: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致. <select id="selectorder" parametertype=&qu ...

  5. redis 亿级查询速度_吊打面试官系列:Redis 性能优化的 13 条军规大全

    我的官方群点击此处. 1.缩短键值对的存储长度 键值对的长度是和性能成反比的,比如我们来做一组写入数据的性能测试,执行结果如下: 从以上数据可以看出,在 key 不变的情况下,value 值越大操作效 ...

  6. vb6 判断打印机是否有效_吊打面试官 | 算法之如何判断括号是否有效?

    今天要讲的这道题是 bilibili 今年的笔试真题,也是一道关于栈的经典面试题. 经过前面文章的学习,我想很多朋友已经看出来了,我接下来要写的是一个关于「算法图解」的系列文章,中间可能会穿插少量的其 ...

  7. atoi函数_吊打面试官 | 腾讯经典考点写代码实现atoi函数

    点击蓝字关注我哦 以下是本期干货视频视频后还附有文字版本哦 ▼<腾讯经典考点-写代码实现atoi函数>▼ ps:请在WiFi环境下打开,如果有钱任性请随意 在腾讯面试时,经常会被问到如何用 ...

  8. 在ABAP XSLT中调用ABAP类的方法

    本文介绍在ABAP XSLT中调用ABAP类的方法. 要获取更多Jerry的原创文章,请关注公众号"汪子熙":

  9. oracle 执行java_oracle调用JAVA类的方法

    oracle调用JAVA类的方法主要有以下三种: 1. 用loadjava方法装载: 可能是调试方便,据说这种方法比较通用. c:\test\hello.java public class hello ...

最新文章

  1. 《中国人工智能学会通讯》——11.72 结束语
  2. Python的函数名作为参数传入调用以及map、reduce、filter
  3. 100万并发连接服务器笔记之测试端就绪
  4. 茶颜只有“霸蛮”,没有悦色
  5. java 高并发im_java高并发(四)并发编程与线程安全
  6. 腾讯二十年了,马化腾定了个新方向!
  7. 洛谷 1429 平面最近点对(加强版) 快排 非点分治或kdtree
  8. 令人失望的智器Smart Q5
  9. 计算机屏保黑屏取消,电脑怎么取消屏保黑屏
  10. 在Ubuntu22.04中安装微信、QQ
  11. html 网页公式编辑软件,LaTeX 公式编辑器网页版
  12. 数字信号传输理论 Nyquist准则
  13. 栈——后进先出(LIFO:last in first out)
  14. 如何把视频语音转换成文字呢?
  15. Android仿抖音加载框之两颗小球转动控件
  16. 降级重新安装低版本flash_player_active_x的方法
  17. matlab常用函数汇总
  18. windows设置开机启动程序
  19. 婚姻就是找个合适的人过日子
  20. WCF各种banding支持的类型

热门文章

  1. 数据结构-动态查找树表与平衡二叉树 红黑树简单介绍
  2. python 错误AttributeError: ‘dict_keys‘ object has no attribute ‘sort‘
  3. alias cli3 配置_vue-cli3项目搭建配置以及性能优化
  4. python实现爬虫下载美女图片
  5. getBoundingClientRect()
  6. mac下php的坑,MAC下安装laravel时遇到的坑
  7. h2 不能访问localhost,SpringBoot访问H2控制台
  8. python函数的目的与意义_Python函数__new__及__init__作用及区别解析
  9. 计算机盘不显示桌面,电脑开机后不显示Windows系统桌面怎么办?
  10. java高级工程师线程_java高级工程师--------多线程并发