1、为什么使用类加载器?
类加载过程都是在运行时完成的,这个过程会增加系统性能的开销,但能够带来灵活性。我们可以在运行期间,通过类加载器,
在程序运行时加载一些class文件。
2、类加载过程?
使用Java编译器将java文件编译为class文件,这个过程不再详细叙述。主要说明我们如何利用这些编译好的
class文件。
JVM将class文件加载到内存,并对数据进行校验、解析和初始化,最终形成JVM可直接使用的Java类型的过程。
加载:
类加载的第一步,这个过程需要类加载参与,需要做下面三件事情:
(1)、通过一个“类全名”来获取其定义的二进制字节流。
(2)、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
(3)、在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口
注意:第(1)中获取二进制字节流不只是单纯地从Class文件中获取,比如它还可以从Jar包中获取、
从网络中获取、由其他文件生成(JSP应用)等。
链接:
将Java类的二进制代码合并到JVM的运行状态之中的过程,这个过程包括:验证、准备和解析三个步骤。
(1)、验证
--目的是为了确保Class文件中的字节流包含的信息符合当前虚拟机的要求,不会危害虚拟机自身的安全。
不同的虚拟机对类验证的实现可能会有所不同,但大致都会完成以下四个阶段的验证:
文件格式的验证、元数据的验证、字节码验证和符号引用验证。
1.文件格式验证
验证class文件格式规范,例如: class文件是否已魔术0xCAFEBABE开头 , 主、次版本号是否在当前虚拟机处理
范围之内等
2.元数据验证
对字节码描述的信息进行语义分析,以保证起描述的信息符合java语言规范要求。验证点可能包括:这个类是否有
父类(除了java.lang.Object之外,所有的类都应当有父类)、这个类是否继承了不允许被继承的类(被final修饰的)、
如果这个类的父类是抽象类,是否实现了起父类或接口中要求实现的所有方法。
3.字节码验证
进行数据流和控制流分析,这个阶段对类的方法体进行校验分析,这个阶段的任务是保证被校验类的方法在运行时
不会做出危害虚拟机安 全的行为。如:保证访法体中的类型转换有效,例如可以把一个子类对象赋值给父类数据类
型,这是安全的,但不能把一个父类对象赋值 给子类数据类型、保证跳转命令不会跳转到方法体以外的字节码命令上。
4.符号引用验证
符号引用中通过字符串描述的全限定名是否能找到对应的类、符号引用类中的类,字段和方法的访问性(private、
protected、public、default)是否可被当前类访问。
(2)、准备
-- 正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配
(3)、解析
-- 虚拟机常量池内的符号引用替换为直接引用的过程
(4)、初始化
是执行类构造<clinit>()方法的过程。
初始化一个类时,如发现其父类还没有进行初始化、则先进行父类的初始化。
虚拟机保证一个类的<clinit>()方法在多线程环境下只执行一次。
当访问一个Java类的静态域时,只有真正声明这个域的类才会初始化。