首先随便找了一个jvm的结构图
类加载器子系统
它包含三个大的阶段
分别是 : 加载(loading) -> 链接(linking) -> 初始化(Initialization)
加载: 通过类的全限定名获取到这个类的二进制字节流 -> 将这个字节流转换成方法区的运行时数据结构
链接: 验证->准备->解析
首先是验证
验证包括验证该class字节流包含的信息符合当前虚拟机的要求 保证被加载类的正确性 不会去危害虚拟机自身安全
主要包括四种验证
文件格式验证(是否以0XCAFEBABE开头)
元数据验证(
1.这个类是否包含父类【java中除了Object 其他类都应该有父类】
2.这个的是否exetends了一个不被运行继承的类 比如final修饰的类
3.如果该类不是抽象类 是否实现了父类【接口】还未实现的方法
4.类中的字段或方法是否与父类产生矛盾 如覆盖了父类的final字段或方法 或者覆盖不符合规则)
准备
类变量(静态变量)分配内存并设置初始值【即0或NULL】
这里不包含final修饰的static 因为final在编译时就会自动分配 准备阶段会显示初始化
例:
这里不会为实例变量分配初始化
静态变量会分配在方法区中 而实例变量会后对象一起分配在堆中
初始化
初始化阶段就是执行类构造器方法(<clinit>)的过程
此方法不需要定义 是javac编译器自动收集类中的所有赋值动作和静态代码块中的语句合并而来
构造器方法中指令按语句在源文件中出现的顺序执行
若该类具有父类 jvm会保证子类执行前 父类的已经初始化完成
class Animal{ static int a = 0; static { a = 10; } } class Cat extends Animal{ static int b =0 ; static { b = a; } } //结果Cat.b为10
虚拟机必须保证一个类的<clinit>方法在多线程中同步加锁