前言
java文件从完成编码到运行结束,需要执行两部分:
- 编译
- 运行
编译:就是将java文件通过javac命令编译成字节码文件,也就是.class文件
运行:将字节码文件交给JVM虚拟机执行的过程
类的加载过程就是将.class文件中的类的信息加载进JVM虚拟机内存中,并进行解析生成class对象的过程。JVM并不是一开始就将所有的.class文件加载进内存中,而是在运行的过程中碰到一个内存中没有的类,才去加载该类的.class文件,且只加载一次。
类加载
类加载的过程分为三部分
- 加载
- 链接(分为三部分)
1. 验证
2. 准备
3. 解析 - 初始化
加载
就是把从各个来源的字节码文件通过类加载器装载到内存中
字节码文件来源:一般是通过本地编译生成的字节码文件,jar包中的字节码文件
类加载器:一般是启动类加载器,扩展类加载器,应用类加载器以及用户自定义的类加载器
自定义类加载器作用:
- java代码很容易反编译,用户可以对编译后的代码进行加密,然后通过自定义的类加载器进行解密,在加载到内存中
- 另一方面也有可能从非标准的来源加载代码,比如从网络来源,那就需要自己实现一个类加载器,从指定源进行加载。
验证
保证加载进来的字符流符合JVM虚拟机规范,不会造成安全错误
准备
为类变量分配内存,并且赋予初值
该初值并不是代码中赋给的值,而是JVM根据不同的数据类型赋给不同的默认的值
八中基本类型默认赋0,引用类型默认为null,常量则是代码中给的值
解析
将常量池中的符号引用替换为直接引用的过程
符号引用:一个字符串,这个字符串是能够唯一识别类,方法,变量的信息
直接引用:一个内存地址或者一个偏移量,类方法,类变量的直接引用是指向方法区的指针,而实例方法,实例变量的直接引用是从实例的头指针到这个实例变量的位置的偏移量。
初始化
这个阶段是对类变量初始化,执行类构造器的过程,只对static修饰的变量或语句进行初始化的过程
如果在初始化子类时其父类并未初始化,则会先初始化父类
如果同时包含多个静态代码块或静态变量,则由上向下依次执行
总结
类加载过程只是类的生命周期的一部分,前面有编译过程,只有对源代码编译完成后才能获得被加载的字节码文件,在其后有类的使用过程,使用完成后还会在方法垃圾区进行回收卸载