类的生命周期
加载 ===> 连接(验证 ==> 准备 ==> 解析 ) ===> 初始化 ===> 使用 ===> 卸载
类的加载过程
1、通过类全类名获取定义该类的二进制字节流
2、将字节流所代表的静态存储结构转换为方法区的运行时数据结构
3、在内存中生成一个Class对象,作为在方法区这些数据的访问入口
验证
1、文件格式验证
验证字节流是否复合Class文件格式的规范,如命名
2、元数据验证
对字节码里的信息和javac编译阶段的语义分析进行对比,看是否复合java语言规范
3、字节码验证
去顶程序语义和合法的、复合逻辑的。
4、符号引号验证
确保解析动作能正确执行。
准备
正式为类变量(static)分配内存并设置默认值的阶段(赋值在初始化阶段)。特殊情况:如果是final修饰的话就会直接赋值,并放在常量池。
解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。也就是得到类或者字段、方法在内存中的指针或者偏移量。
初始化
初始化是类加载的最后一个阶段。初始化是为类的静态变量赋予正确的初始值。
对于初始化阶段,虚拟机严格规范了有且只有5种情况下,必须对类进行初始化(只有主动去使用类才会初始化类):
1、遇到new 、getstatic、putstatic 或者invokestatic这4条直接指令时进行初始化。也就是:创建一个实例、读取静态变量、给静态变量赋值、调用静态方法时。
2、通过反射对类进行调用时,如调用Class.forName(""),new Instance等方法时。如果类没初始化,需要触发其初始化。
3、初始化一个类时,如果父类没有初始化,会先触发父类的初始化。
4、还有main方法的类会先直接被虚拟机初始化。
5、MethodHandle和varHandle可以看做是轻量级的反射调用机制,要使用这两个调用,必须先进行初始化类
卸载
卸载类需要满足3个条件:
1、类的所有实例已经被GC
2、类没有被任何地方引用
3、类的类加载器的实例已经被GC