面试题:讲一讲Java类加载机制,双亲委派机制的作用是什么,什么情况下需要破坏?
面试题常规回答
JVM在需要使用到类的时候,就先将“.class”字节码文件加载到内存,然后验证文件头是否正确,再解析代码,将成员变量全部赋值为默认值,最后就是初始化阶段,如果有static代码块则在这时候执行。
双亲委派机制就是防止重复加载类,热加载类的时候需要破坏。
面试题深入剖析
Java类的加载完整过程:加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载。
加载:将“.class”字节码文件加载到内存。
验证:校验加载的class文件是否符合规范。
准备:给静态变量static分配内存空间和初始值。比如int设置为0,object设置为null。
解析:将符号引用替换为直接引用,过程比较复杂,大概就是关联到JVM的具体内存偏移量,便于直接操作内存。
初始化:这个阶段最重要,先举个例子:
public class UsersModel {
private Integer id = 1;
private String name = "张三";
}
这里面 id = 1和name = “张三” 就是在这一阶段进行赋值的。当然如果有父类,是先执行父类的初始化。
使用和卸载阶段知道就好了,不用深究。
上面的过程都是依靠类加载器来实现的,不同的类加载器加载的同一个class文件的话,equals判断结果也是false的。
那么双亲委派机制是什么呢?
双亲委派机制就是加载类的时候是先层层上报:
应用程序类加载器(上一级能加载吗?) -> 扩展类加载器(上一级能加载吗?)-> 启动类加载器(我能加载吗?)
如果有一级能加载的就直接加载了,并返回类对象。如果不能则层层下传:
启动类加载器(我不能加载,你自己试试)-> 扩展类加载器(我不能加载,你自己试试)-> 应用程序类加载器(我自己试试)。
一般除了Java内置提供的类,开发人员自己创建的类都是 应用程序类加载器 加载的。
这就引发了另一个问题,我能做到发布在生产环境的class文件能够根据需要替换为最新的吗?也即是怎么做到热部署?
答案是自己实现一个自定义的类加载器,然后在生产环境替换好class文件之后,触发一下重新加载类就能做到热部署。
Tomcat内部其实就是这样做的,自己实现了一套类加载器,可以监听JSP文件的变化,然后重新加载最新的JSP文件。
后面我们也会分享JVM-Sandbox是如何做到更牛逼的字节码插桩,更方便地实现替换类方法。