7.1JVM类加载机制
虚拟机把数据从Class文件加载到内存,并且校验、转换解析和初始化最终形成可以被虚拟机使用的Java类型,这就是虚拟机的类加载机制。
7.2类加载的时机
加载(Loading) -> 验证(Verification) -> 准备(Preparation) -> 解析(Resolution) -> 初始化(Initialization) -> 使用(Using) -> 卸载(Unloading) ,验证、准备、解析的过程称为 链接
2.关于初始化阶段,有5种情况需要立即进行初始化:
(1)遇到这四个字节码指令时:new、getstatic、putstatic、invokestatic,如果类未进行过初始化,那么进行初始化,这几个字节码指令所在场景:new对象、调用类的静态属性、调用类的静态方法;
java.lang.reflect
(3)当初始化一个类时,其父类未进行初始化时,对其父类进行初始化;
(4)虚拟机启动时需要初始化一个指定的主类(包含main()方法的类);
java.lang.invoke.MethodHandle 实例的解析结果为 REF_getStatic 、 REF_putStatic 、 REF_invokeStatic
主动引用 ,而其他的引用类的方式则不会初始化类,它们叫做 被动引用
(1)使用子类访问父类的静态属性时,不会初始化子类;
(2)创建一个类的数组时,不会初始化此类,但是会初始化出一个另外的类,代表这个数组对象;
(3)访问一个类的静态常量时,不会初始化这个类,这个静态常量进入常量池会被归属给NonInitialization类的常量池中,代表不会初始化;
7.3类加载的过程
1.加载:
(1)通过类的全限定名来获取Class文件的二进制流;
(2)将这个字节流根据虚拟机所需要的存储结构存放在内存中;
java.lang.Class
2.验证:
虽然Java代码的编译过程不允许一些不安全的做法(C/C++常做),比如:访问数组边界以外的数据、错误的对象转型、跳转到不存在的行,但是不能保证Class文件不被修改,所以验证这一步骤作为连接的第一个阶段对于JVM的安全性来说非常重要;
文件格式验证 、 元数据验证 、 字节码验证 、 符号引用验证
(1)文件格式验证:①验证魔数;②主、次版本号;③长度检查;等等
java.lang.Object
(3)字节码验证:①验证错误的对象转型;②跳转到不存在的行;等等
直接引用
3.准备:
准备阶段是为类变量(static修饰)分配内存并赋予初始值的阶段;
public static int i = 1; 这里的 i
public static final int i = 1; 而这里的 i在准备阶段之后赋值为1;
4.解析:
符号引用 转换为 直接引用 的过程,分为 类或接口解析 、 字段解析 、 类方法解析 、 接口方法解析
5.初始化:
<cinit>() 方法,对应 static{}
(1)<cinit>()方法只能访问到static{}代码块前面的变量,而在static后面的变量,只能赋值,不能访问引用(非法向前引用);
(2)子类初始化,会默认先初始化父类来调用父类的<cinit>()方法;
(3)一般类中没有static{}代码块,那么也就不会生成<cinit>()方法;
(4)接口不能写static{}代码块,但是赋值给变量时也会生成<cinit>()方法;
(5)<cinit>()方法是同步的,线程安全的。
7.4类加载器
类加载器 作用于 加载
1.关于类和类加载器:
equals()
2.双亲委派模型:
(1)三种系统的类加载器:
%JAVA_HOME%/lib 下和 -Xbootclasspath
%JAVA_HOME%/lib/ext 目录下和 java.ext.dirs
③ 应用程序类加载器(Application ClassLoader):加载用户类路径下的类库;
(2)双亲委派模型:
启动类加载器(Bootstrap ClassLoader) 以外,其它类加载器都要有自己的父加载器,它们之间不是 继承 关系,而是 组合
(3)双亲委派机制工作过程:
父类加载器 请求加载,依次类推,直到顶层类加载器,只有当类加载器不能加载此类时才会让 子类加载器
(4)双亲委派机制的意义:
java.lang.String 类,系统只加载了jdk默认的 java.lang.String 的类文件,而不会加载自己写的java.lang.String类;
3.破坏双亲委派模型:
ClassLoader
loadClass() 方法,在 parent.loadClass()