类加载器是用来把类 class 装载入 JVM 。
类从被加载到JVM中开始,到卸载为止,整个生命周期包括 :加载、验证、准备、解析、初始化、使用和卸载七个阶段 。
其中类加载过程包括: 加载、验证、准备、解析和初始化 五个阶段。
类加载器的任务
就是根据一个类的全限定名来读取此类的二进制字节流到JVM中,然后转换为一个与目标类对应的 Java .lang.Class对象实例。
defineClass方法将字节码的byte数组转换为一个类的class对象实例,如果希望在类被加载到JVM时就被链接,那么可以调用resolveClass方法。
自定义类加载器
需要继承抽象类ClassLoader,实现findClass方法,该方法会在loadClass调用的时候被调用,findClass默认会抛出异常。
findClass方法表示根据类名查找类对象;
loadClass方法表示根据类名和双亲委托模型进行类加载并返回类对象;
defineClass方法表示跟根据类的字节码转换为类对象;
双亲委托模型 Parents Delegation Model
更好的保证 JAVA 平台的安全。在此模型下,当一个装载器被请求加载某个类时,先委托自己的 parent 去装载,如果 parent 能装载,则返回这个类对应的 Class 对象,否则,递归委托给父类的父类装载。
在此模型下,用户自定义的类装载器,不可能装载应该由父亲装载的可靠类,从而防止不可靠甚至恶意的代码代替本应该由父亲装载器装载的可靠代码。
最高一层是家族中威望最高的Bootstrap,它是在 JVM 启动时创建的,通常由与操作系统相关的本地代码实现,是最根基的类加载器,负责加载最核心的Java类,如Object、System、String等等。
双亲委托模型的工作过程:
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委托给父类加载器去完成,每一个层次的类加载器都是如此。因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需要加载的类)时,子加载器才会尝试自己去加载。
使用双亲委托机制的好处是:能够有效确保一个类的全局唯一性,当程序中出现多个限定名相同的类时,类加载器在执行加载时,始终只会加载其中的某一个类。
查看本地类加载器的方式:
ClassLoader c = ClassTest. class .getClassLoader();
System. out .println(c);
ClassLoader c1 = c.getParent();
System. out .println(c1);
ClassLoader c2 = c1.getParent();
// 父加载器是Bootstrap,它使用C++ 来实现,返回null
System. out .println(c2);
输出结果:
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@677327b6
null
《深入理解java虚拟机》
字节码(Bytecode) 必须通过类加载过程,加载到JVM 环境后,才可以执行。
JIT 编译技术
JVM 通过热点代码统计分析,基于强大的JIT 动态编译技术,将热点代码转换成机器码,直接交给CPU 执行。
JIT 的作用:
将Java 字节码动态地编译成可以直接发给CPU 指令执行的机器码。
热机状态、冷机状态(刚启动时)
刚启动的JVM 均是解释执行,还没有进行热点代码统计和 JIT 动态编译。
双亲委托模型
向上询问是否已加载;
逐层尝试是否可加载;
如下代码,可以查看Bootstrap 所有已经加载的类库:
URL[] urls = sun.misc.Launcher. getBootstrapClassPath ().getURLs();
for (URL url : urls){
System. out .println(url.toExternalForm());
}
输出结果:
file:/C:/Java/jdk1.8.0_111/jre/lib/resources.jar
file:/C:/Java/jdk1.8.0_111/jre/lib/rt.jar
file:/C:/Java/jdk1.8.0_111/jre/lib/sunrsasign.jar
file:/C:/Java/jdk1.8.0_111/jre/lib/jsse.jar
file:/C:/Java/jdk1.8.0_111/jre/lib/jce.jar
file:/C:/Java/jdk1.8.0_111/jre/lib/charsets.jar
file:/C:/Java/jdk1.8.0_111/jre/lib/jfr.jar
file:/C:/Java/jdk1.8.0_111/jre/classes