一、类的加载
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
二、类的生命周期
类的加载、连接和初始化过程都是在程序运行期间完成的。
这个时候类加载的全过程,包括加载、验证、准备、解析和初始化、使用和卸载7个结算,其中验证、准备、解析3个部分统称为连接。
“加载”是“类加载”过程的一个阶段。加载使用的是双亲委派机制。加载阶段,虚拟机需要完成以下三件事情,
1)、通过一个类的全限定名来获取定义此类的二进制字节流
2)、将这个字节流所代表的的静态存储结构转化为方法区的运行时数据结构。
3)、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
这个类加载的过程主要是由类加载器来完成的。
验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
1)、文件格式验证:基于字节流验证
2)、元数据验证:基于方法区的存储结构验证
3)、字节码验证:基于方法区的存储结构验证
4)、符号引用验证:基于方法区的存储结构验证
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。
直接引用可以是指向目标的指针,相对偏移量或是一个能间接定位目标的句柄。
初始化,类初始化阶段是类加载过程的最后一步,才真正开始执行类中定义的Java程序代码
三、类的加载器
类加载器虽然只用于实现类的加载动作,对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。比较两个类是否相等,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载他们的类加载器不同,那这两个类就必定不相等。
自带的类加载器有三种:
1)、启动类加载器
2)、扩展类加载器
3)、应用程序类加载器
四、双亲委派机制
1)、BootstrapClassLoader:启动类加载器,该ClassLoader是jvm在启动时创建的,用于加载/jre/lib下面的类库,
2)、ExtClassLoader:扩展类加载器,会加载ExtClassLoader会加载/jre/ext下的类库
3)、AppClassLoader:应用程序类加载器,会加载java环境变量CLASSPATH所指定的路径下的类库,
4)、CustomClassLoader:自定义类加载器,该ClassLoader是指我们自定义的ClassLoader
双亲委派机制
1)、当AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成
2)、当ExtClassLoader加载一个class时,它首先也不会自己尝试去加载这个类,而是把类加载请求委派给父类加载器BootStrapClassLoader去完成
3)、如果BootStrapClassLoader加载失败,在/jre/lib里未找到该class,会使用ExtClassLoader来尝试加载
4)、若ExtClassLoader也加载失败,则会使用AppClassLoader来加载,如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException。